From 594e9f1a5ee2037cee96c7faa0057a08988e82e6 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 18 Jan 2024 14:36:52 -0800 Subject: [PATCH 01/28] eable ap --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index cd8a31a..8997360 100644 --- a/platformio.ini +++ b/platformio.ini @@ -52,7 +52,7 @@ build_flags = ${env.build_flags} '-D CAMERA_MODEL_M5STACK_PSRAM' '-D NAME="GROUNDLIGHT_DEMO_UNIT"' -# '-D ENABLE_AP' + '-D ENABLE_AP' lib_deps = ${env.lib_deps} https://github.com/me-no-dev/ESPAsyncWebServer.git#master From 181a1539101b8f806fba6bd704bd476460008c53 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 18 Jan 2024 15:29:27 -0800 Subject: [PATCH 02/28] hide password --- src/deployable_example.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 49daaf7..0365c1c 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -298,7 +298,7 @@ const char index_html[] PROGMEM = R"rawliteral(
WiFi SSID: - WiFi Password: + WiFi Password: Detector Id: API Key: Query Delay (seconds): From 59ab9e51ab9ef1069332d44c89fec3de7842ad9e Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 18 Jan 2024 16:33:58 -0800 Subject: [PATCH 03/28] added autocofig checkbox --- src/deployable_example.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 0365c1c..e4589b0 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -299,8 +299,15 @@ const char index_html[] PROGMEM = R"rawliteral( WiFi SSID: WiFi Password: + API Key: + + + + Detector Id: - API Key: Query Delay (seconds): Endpoint: Target Confidence: @@ -367,6 +374,7 @@ String processor(const String& var) { preferences.end(); return out; // return var; + } #endif From 3311159188cbb9570ed4d4a0789afff69e139cd4 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Sun, 28 Jan 2024 22:27:14 -0800 Subject: [PATCH 04/28] added autoconfig checkbox --- src/deployable_example.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index e4589b0..18bb516 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -299,14 +299,11 @@ const char index_html[] PROGMEM = R"rawliteral( WiFi SSID: WiFi Password: - API Key: - - + API Key: - Detector Id: Query Delay (seconds): Endpoint: @@ -374,7 +371,6 @@ String processor(const String& var) { preferences.end(); return out; // return var; - } #endif @@ -649,6 +645,7 @@ void setup() { #endif } + void listener(void * parameter) { char input3[1000]; int input3_index = 0; @@ -1340,4 +1337,4 @@ bool is_motion_detected(camera_fb_t* frame, int alpha, int beta) { } return motion_detected; -} +} \ No newline at end of file From a12ab27a8665506b285a1f354fe8485db9b8c058 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 1 Feb 2024 13:59:43 -0800 Subject: [PATCH 05/28] Check required input was met before initiating auto-config --- src/deployable_example.cpp | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 18bb516..5cfdce2 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -349,6 +349,7 @@ String processor(const String& var) { // String out = String(); String out = ""; // if (var == "ssid") return String(ssid); + // update data filled the form chart and store in preferences locally. if (var == "ssid") out = ssid; else if (var == "password") out = password; else if (var == "det_id") out = groundlight_det_id; @@ -368,12 +369,26 @@ String processor(const String& var) { else if (var == "twilio_token" && preferences.isKey("twilioKey")) out = preferences.getString("twilioKey", ""); else if (var == "twilio_number" && preferences.isKey("twilioNumber")) out = preferences.getString("twilioNumber", ""); else if (var == "twilio_recipient" && preferences.isKey("twilioEndpoint")) out = preferences.getString("twilioEndpoint", ""); + else if (var == "autoconfig" && preferences.isKey("autoconfig")) out = preferences.getString("autoconfig", ""); preferences.end(); return out; // return var; } #endif - +//define a auto configuration method: +void performAutoConfig(AsyncWebServerRequest *request) { + Serial.println("Running autoconfig..."); + // Check for required parameters and if autoconfig is enabled + if (request->hasParam("autoconfig") && + request->hasParam("ssid") && !request->getParam("ssid")->value().isEmpty() && + request->hasParam("pw") && !request->getParam("pw")->value().isEmpty() && + request->hasParam("api_key") && !request->getParam("api_key")->value().isEmpty()) { + // debug only: + Serial.println("Autoconfig is enabled."); + // Auto-fill logic starts here + // preferences.putInt("query_delay", 10); // Default value in seconds +} +} void setup() { Serial.begin(115200); @@ -458,11 +473,14 @@ void setup() { // Send web page with input fields to client // at http://192.168.4.1/ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send_P(200, "text/html", index_html, processor); - }); + //call autoConfig function: + performAutoConfig(request); + request->send_P(200, "text/html", index_html, processor); + }); server.on("/config", HTTP_GET, [] (AsyncWebServerRequest *request) { - preferences.begin("config", false); + //TODO: set preferences to true? + preferences.begin("config", false); if (request->hasParam("ssid") && request->getParam("ssid")->value() != "") { preferences.putString("ssid", request->getParam("ssid")->value()); strcpy(ssid, request->getParam("ssid")->value().c_str()); @@ -527,7 +545,10 @@ void setup() { if (request->hasParam("twilio_recipient") && request->getParam("twilio_recipient")->value() != "") { preferences.putString("twilioEndpoint", request->getParam("twilio_recipient")->value()); } - // request->send(200, "text/html", "Configuration sent to your ESP Camera
Return to Home Page"); + if (request->hasParam("autoconfig") && request->getParam("autoconfig")->value() != "") { + preferences.putString("autoconfig", request->getParam("autoconfig")->value()); + } + request->send(200, "text/html", "Configuration sent to your ESP Camera
Return to Home Page"); request->send_P(200, "text/html", sent_html); preferences.end(); }); From cbaa34d3180a6fa0c6503125bede00a568e04ef1 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Sat, 10 Feb 2024 15:53:01 -0800 Subject: [PATCH 06/28] fixed get_detector_list --- .gitignore | 4 +- lib/groundlight/src/groundlight.cpp | 43 ++++++++++++-- lib/groundlight/src/groundlight.h | 6 +- src/deployable_example.cpp | 92 +++++++++++++++++++---------- 4 files changed, 105 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index c52458c..01ee838 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ .vscode/ipch .DS_Store -src/credentials.h \ No newline at end of file +src/credentials.h + +config/ \ No newline at end of file diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index 58e2a45..cb50c93 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -369,18 +369,37 @@ StaticJsonDocument groundlight_json_doc; // Parses the detectors from the Groundlight API. detector_list get_detector_list(const char *endpoint, const char *apiToken) { - deserializeJson(groundlight_json_doc, get_detectors(endpoint, apiToken)); - JsonArray detectors = groundlight_json_doc["results"]; + String jsonResponse = get_detectors(endpoint, apiToken); + // deserializeJson(groundlight_json_doc, get_detectors(endpoint, apiToken)); + //debug parsing: + auto error = deserializeJson(groundlight_json_doc, jsonResponse); + if (error) { + Serial.print("deserializeJson() failed: "); + Serial.println(error.c_str()); + return {}; // Return an empty detector_list if parsing fails + } + //if it is not empty: + JsonArray detectors = groundlight_json_doc["results"]; //json -> array detector *_detector_list = new detector[detectors.size()]; for (int i = 0; i < detectors.size(); i++) { - _detector_list[i].confidence_threshold = detectors[i]["confidence_threshold"]; + JsonObject detectorObj = detectors[i]; //detector + + _detector_list[i].confidence_threshold = detectors[i]["confidence_threshold"]; //float or str? strcpy(_detector_list[i].id, detectors[i]["id"]); strcpy(_detector_list[i].type, detectors[i]["type"]); strcpy(_detector_list[i].created_at, detectors[i]["created_at"]); strcpy(_detector_list[i].name, detectors[i]["name"]); strcpy(_detector_list[i].query, detectors[i]["query"]); strcpy(_detector_list[i].group_name, detectors[i]["group_name"]); + // serialize and copy metadata + if (!detectorObj["metadata"].isNull()) { + String metadataStr; + serializeJson(detectorObj["metadata"], metadataStr); + strlcpy(_detector_list[i].metadata, metadataStr.c_str(), sizeof(_detector_list[i].metadata)); + } else { + _detector_list[i].metadata[0] = '\0'; //set to an empty string if metadata is null. + } } detector_list res = { _detector_list, detectors.size() }; return res; @@ -401,16 +420,28 @@ String detector_to_string(detector d) { res += d.group_name; res += "\n\tConfidence threshold: "; res += d.confidence_threshold; + res += "\n\tMetadata: "; //added metadata + res += d.metadata; return res; } -detector get_detector_by_id(const char *endpoint, const char *detectorId, const char *apiToken) { +detector get_detector_by_id(const char *endpoint, const char *detector_id, const char *apiToken) { detector_list detectors = get_detector_list(endpoint, apiToken); for (int i = 0; i < detectors.size; i++) { - if (String(detectors.detectors[i].id) == String(detectorId)) { + if (String(detectors.detectors[i].id) == String(detector_id)) { return detectors.detectors[i]; } } - return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0 }; + return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; +} + +detector get_detector_by_name(const char *endpoint, const char *detectorName, const char *apiToken) { //given input: detectorName + detector_list detectors = get_detector_list(endpoint, apiToken); + for (int i = 0; i < detectors.size; i++) { + if (String(detectors.detectors[i].name) == String(detectorName)) { + return detectors.detectors[i]; + } + } + return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; } #endif \ No newline at end of file diff --git a/lib/groundlight/src/groundlight.h b/lib/groundlight/src/groundlight.h index ee438a6..0ff2f78 100644 --- a/lib/groundlight/src/groundlight.h +++ b/lib/groundlight/src/groundlight.h @@ -33,9 +33,10 @@ struct detector char created_at[60]; char name[40]; char query[200]; - char group_name[40]; + char group_name[40]; float confidence_threshold; -}; + char metadata[1024]; // +}; struct detector_list { @@ -46,6 +47,7 @@ struct detector_list detector_list get_detector_list(const char *endpoint, const char *apiToken); String detector_to_string(detector d); detector get_detector_by_id(const char *endpoint, const char *detectorId, const char *apiToken); +detector get_detector_by_name(const char *endpoint, const char *detectorName, const char *apiToken);// float get_query_confidence(const String &jsonResults); String get_query_id(const String &jsonResults); #endif \ No newline at end of file diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 5cfdce2..b9de9d0 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -1,28 +1,28 @@ -/* +// /* -Groundlight deployable example of image classification from a visual query. Provided under MIT License below: +// Groundlight deployable example of image classification from a visual query. Provided under MIT License below: -Copyright (c) 2023 Groundlight, Inc. +// Copyright (c) 2023 Groundlight, Inc. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. -*/ +// */ #include #include @@ -36,6 +36,8 @@ SOFTWARE. #include "integrations.h" #include "stacklight.h" +#include "../config/api_keys.h" //testing only + #ifdef PRELOADED_CREDENTIALS #include "credentials.h" #endif @@ -169,7 +171,7 @@ int query_delay = 30; // 30 seconds int start_hr = 8; int end_hr = 17; -bool disable_deep_sleep_for_notifications = false; +bool disable_deep_sleep_for_notifications = false; bool disable_deep_sleep_until_reset = false; float targetConfidence = 0.9; int retryLimit = 10; @@ -374,21 +376,26 @@ String processor(const String& var) { return out; // return var; } -#endif -//define a auto configuration method: + +// Web form auto configuration method: void performAutoConfig(AsyncWebServerRequest *request) { Serial.println("Running autoconfig..."); - // Check for required parameters and if autoconfig is enabled + // Check autoconfig parameter if (request->hasParam("autoconfig") && - request->hasParam("ssid") && !request->getParam("ssid")->value().isEmpty() && - request->hasParam("pw") && !request->getParam("pw")->value().isEmpty() && - request->hasParam("api_key") && !request->getParam("api_key")->value().isEmpty()) { - // debug only: - Serial.println("Autoconfig is enabled."); - // Auto-fill logic starts here - // preferences.putInt("query_delay", 10); // Default value in seconds + request->hasParam("ssid") && !request->getParam("ssid")->value().isEmpty() && + request->hasParam("pw") && !request->getParam("pw")->value().isEmpty() && + request->hasParam("api_key") && !request->getParam("api_key")->value().isEmpty()) { + // debug print: + Serial.println("Autoconfig is enabled."); + // get_detector_by_name: + String detectorName = "ESP32-CAM-87E1AC"; + // String metadataJson = get_detector_by_name() + // get the metadata, serialize it in json string; + // deserialize the json string, parse configs -> preferences library & server. } } +#endif + void setup() { Serial.begin(115200); @@ -474,7 +481,7 @@ void setup() { // at http://192.168.4.1/ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ //call autoConfig function: - performAutoConfig(request); + // performAutoConfig(request); request->send_P(200, "text/html", index_html, processor); }); @@ -813,6 +820,29 @@ void loop () { } if (WiFi.isConnected()) { debug_printf("WIFI connected to SSID %s\n", ssid); + //Testing: + const char* endpoint = "api.groundlight.ai"; + const char* apiToken = API_TOKEN; + String detectors = get_detectors(endpoint, apiToken); + Serial.println(detectors); + //test: + detector_list det_list = get_detector_list(endpoint, apiToken); + Serial.println(det_list.size); //parsing succeeded. + // Check if 'get_detector_by_list' is working: + Serial.println(det_list.detectors[0].id); + + Serial.println(det_list.detectors[0].metadata); //succeeded! + //check if 'get_detector_by_id' is working: + // const char* detector_id = det_list.detectors[0].id; + // detector det = get_detector_by_id(endpoint,detector_id,apiToken); + // Serial.println("get detector by id: "); + // Serial.print(det.name);//succeeded! + //check 'get_detector_by_name': + const char* detectorName = det_list.detectors[0].name; + detector det = get_detector_by_name(endpoint,detectorName,apiToken); + Serial.println("get detector id by name: "); + Serial.print(det.id);//succeeded! + } else { debug_printf("unable to connect to wifi status code %d! (skipping image query and looping again)\n", WiFi.status()); return; From 7a062dca8535ddfa4a636b9e0ca7dc7666576144 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Tue, 13 Feb 2024 09:50:16 -0800 Subject: [PATCH 07/28] added metadata debug prints --- credentials/api_keys.h | 6 +++ src/deployable_example.cpp | 105 ++++++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 credentials/api_keys.h diff --git a/credentials/api_keys.h b/credentials/api_keys.h new file mode 100644 index 0000000..99214e3 --- /dev/null +++ b/credentials/api_keys.h @@ -0,0 +1,6 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define API_TOKEN "api_2apcwsQuXcq8ySCMelpMxdMxmP2_QL2ht1ddZRFaWrfa3QsCHMHtWgeJ5SF9n5"; + +#endif \ No newline at end of file diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index b9de9d0..dfc728e 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -33,10 +33,10 @@ #include "groundlight.h" #include "camera_pins.h" // thank you seeedstudio for this file -#include "integrations.h" +#include "integrations.h" #include "stacklight.h" -#include "../config/api_keys.h" //testing only +#include "../credentials/api_keys.h" //testing only #ifdef PRELOADED_CREDENTIALS #include "credentials.h" @@ -172,7 +172,7 @@ int start_hr = 8; int end_hr = 17; bool disable_deep_sleep_for_notifications = false; -bool disable_deep_sleep_until_reset = false; +bool disable_deep_sleep_until_reset = true; //true for testing float targetConfidence = 0.9; int retryLimit = 10; @@ -376,24 +376,63 @@ String processor(const String& var) { return out; // return var; } - -// Web form auto configuration method: void performAutoConfig(AsyncWebServerRequest *request) { - Serial.println("Running autoconfig..."); - // Check autoconfig parameter - if (request->hasParam("autoconfig") && - request->hasParam("ssid") && !request->getParam("ssid")->value().isEmpty() && - request->hasParam("pw") && !request->getParam("pw")->value().isEmpty() && - request->hasParam("api_key") && !request->getParam("api_key")->value().isEmpty()) { - // debug print: - Serial.println("Autoconfig is enabled."); - // get_detector_by_name: - String detectorName = "ESP32-CAM-87E1AC"; - // String metadataJson = get_detector_by_name() - // get the metadata, serialize it in json string; - // deserialize the json string, parse configs -> preferences library & server. -} + const char* detectorName = "cat"; //testing only + //convert apiToken: + Serial.println("Auto config starts running.");//debug + // String apiTokenString = API_TOKEN; + const char* apiToken = API_TOKEN; + detector espCamDet = get_detector_by_name("api.groundlight.ai", detectorName, apiToken); + //parse det_id: + String esp_id = espCamDet.id; + preferences.putString("det_id", esp_id); + Serial.println("Autofilled Det_id is: "); + Serial.println(esp_id); + //parse metadata: + String metadataString = espCamDet.metadata; + if (metadataString.length() > 0) { + // deserialze metadata: + DynamicJsonDocument metadataDoc(1024); + deserializeJson(metadataDoc, metadataString); + // if existed, e.g., parse det_id : + if (metadataDoc.containsKey("Query Delay (seconds)") &&!metadataDoc["Query Delay (seconds)"].isNull()){ + int esp_query_delay = metadataDoc["Query Delay (seconds)"]; + //debug: + Serial.println("Get query_delay from metadata:"); + Serial.println(query_delay); + //put query_delay value in preferences: + preferences.putInt("query_delay", esp_query_delay); + } + //endpoint: + if (metadataDoc.containsKey("Endpoint") &&!metadataDoc["Endpoint"].isNull()){ + String esp_endpoint = metadataDoc["Endpoint"]; + //debug: + Serial.println("Endpoint:"); + Serial.println(esp_endpoint); + //store in preferences + preferences.putString("endpoint", esp_endpoint); + } + //target confidence: + if(metadataDoc.containsKey("Target Confidence") &&!metadataDoc["Target Confidence"].isNull()){ + float esp_tconf = metadataDoc["Target Confidence"]; + //debug: + Serial.println("target confidence:"); + Serial.println(esp_tconf); + ////store in preferences + preferences.putFloat("tconf", esp_tconf); + } + //optional: motion alpha, motion beta, stacklight UUID + } + + + + // fill it in the form + //saving the form values to preferences, similar to the existing '/config' handling logic } +void autosimulation() { + Serial.println("test test test"); + } + #endif void setup() { @@ -480,18 +519,26 @@ void setup() { // Send web page with input fields to client // at http://192.168.4.1/ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - //call autoConfig function: - // performAutoConfig(request); request->send_P(200, "text/html", index_html, processor); }); server.on("/config", HTTP_GET, [] (AsyncWebServerRequest *request) { - //TODO: set preferences to true? - preferences.begin("config", false); + //test: + performAutoConfig(request); + + //IF: + //check: run autoconfig or not + if (request->hasParam("ssid", true) && request->hasParam("pw", true) && request->hasParam("api_key", true)) { + performAutoConfig(request); + Serial.println("auto config runs!"); + } + + //ELSE: + preferences.begin("config", false); //can write? if (request->hasParam("ssid") && request->getParam("ssid")->value() != "") { preferences.putString("ssid", request->getParam("ssid")->value()); strcpy(ssid, request->getParam("ssid")->value().c_str()); - } + } if (request->hasParam("pw") && request->getParam("pw")->value() != "") { preferences.putString("password", request->getParam("pw")->value()); strcpy(password, request->getParam("pw")->value().c_str()); @@ -500,6 +547,9 @@ void setup() { preferences.putString("det_id", request->getParam("det_id")->value()); strcpy(groundlight_det_id, request->getParam("det_id")->value().c_str()); } + //request -hasparam check request has the key; request - get param check request has the value; + //pref.putstring: put 'det_id' inside NVS where ssid is key; request ->getparam is value; + //copy value into 'groundlight_get_id" if (request->hasParam("api_key") && request->getParam("api_key")->value() != "") { preferences.putString("api_key", request->getParam("api_key")->value()); strcpy(groundlight_API_key, request->getParam("api_key")->value().c_str()); @@ -555,6 +605,7 @@ void setup() { if (request->hasParam("autoconfig") && request->getParam("autoconfig")->value() != "") { preferences.putString("autoconfig", request->getParam("autoconfig")->value()); } + request->send(200, "text/html", "Configuration sent to your ESP Camera
Return to Home Page"); request->send_P(200, "text/html", sent_html); preferences.end(); @@ -820,7 +871,7 @@ void loop () { } if (WiFi.isConnected()) { debug_printf("WIFI connected to SSID %s\n", ssid); - //Testing: + //Testing only: const char* endpoint = "api.groundlight.ai"; const char* apiToken = API_TOKEN; String detectors = get_detectors(endpoint, apiToken); @@ -842,6 +893,10 @@ void loop () { detector det = get_detector_by_name(endpoint,detectorName,apiToken); Serial.println("get detector id by name: "); Serial.print(det.id);//succeeded! + + //deserialize matadata + String metadataString = det_list.detectors[0].metadata; + } else { debug_printf("unable to connect to wifi status code %d! (skipping image query and looping again)\n", WiFi.status()); From d73f6945cfe3e75c33c6b0881a9ea1a771fd830d Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 19 Feb 2024 12:20:07 -0800 Subject: [PATCH 08/28] added autoconfig method --- lib/groundlight/src/groundlight.h | 1 - src/deployable_example.cpp | 289 ++++++++++++++---------------- 2 files changed, 139 insertions(+), 151 deletions(-) diff --git a/lib/groundlight/src/groundlight.h b/lib/groundlight/src/groundlight.h index 0ff2f78..5161e4f 100644 --- a/lib/groundlight/src/groundlight.h +++ b/lib/groundlight/src/groundlight.h @@ -43,7 +43,6 @@ struct detector_list detector *detectors; uint size; }; - detector_list get_detector_list(const char *endpoint, const char *apiToken); String detector_to_string(detector d); detector get_detector_by_id(const char *endpoint, const char *detectorId, const char *apiToken); diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index dfc728e..d884ef2 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -304,7 +304,7 @@ const char index_html[] PROGMEM = R"rawliteral( API Key: Detector Id: Query Delay (seconds): @@ -351,7 +351,7 @@ String processor(const String& var) { // String out = String(); String out = ""; // if (var == "ssid") return String(ssid); - // update data filled the form chart and store in preferences locally. + // Fetch previously saved data, filled the form chart and store in preference library. if (var == "ssid") out = ssid; else if (var == "password") out = password; else if (var == "det_id") out = groundlight_det_id; @@ -376,62 +376,75 @@ String processor(const String& var) { return out; // return var; } -void performAutoConfig(AsyncWebServerRequest *request) { - const char* detectorName = "cat"; //testing only - //convert apiToken: - Serial.println("Auto config starts running.");//debug - // String apiTokenString = API_TOKEN; + +//check if meet autoconfig requirment: +bool shouldPerformAutoConfig(AsyncWebServerRequest *request) { + bool autoconfigEnabled = request->hasParam("autoconfig"); + bool ssidFilled = request->hasParam("ssid") && request->getParam("ssid")->value() != ""; + bool passwordFilled = request->hasParam("pw") && request->getParam("pw")->value() != ""; + bool apiKeyFilled = request->hasParam("api_key") && request->getParam("api_key")->value() != ""; + + return autoconfigEnabled && ssidFilled && passwordFilled && apiKeyFilled; +} + +//perform autoconfig: +void performAutoConfig(AsyncWebServerRequest *request){ + const char* endpoint = groundlight_endpoint; const char* apiToken = API_TOKEN; - detector espCamDet = get_detector_by_name("api.groundlight.ai", detectorName, apiToken); - //parse det_id: - String esp_id = espCamDet.id; - preferences.putString("det_id", esp_id); - Serial.println("Autofilled Det_id is: "); - Serial.println(esp_id); - //parse metadata: - String metadataString = espCamDet.metadata; - if (metadataString.length() > 0) { - // deserialze metadata: - DynamicJsonDocument metadataDoc(1024); - deserializeJson(metadataDoc, metadataString); - // if existed, e.g., parse det_id : - if (metadataDoc.containsKey("Query Delay (seconds)") &&!metadataDoc["Query Delay (seconds)"].isNull()){ - int esp_query_delay = metadataDoc["Query Delay (seconds)"]; - //debug: - Serial.println("Get query_delay from metadata:"); - Serial.println(query_delay); - //put query_delay value in preferences: - preferences.putInt("query_delay", esp_query_delay); - } - //endpoint: - if (metadataDoc.containsKey("Endpoint") &&!metadataDoc["Endpoint"].isNull()){ - String esp_endpoint = metadataDoc["Endpoint"]; - //debug: - Serial.println("Endpoint:"); - Serial.println(esp_endpoint); - //store in preferences - preferences.putString("endpoint", esp_endpoint); - } - //target confidence: - if(metadataDoc.containsKey("Target Confidence") &&!metadataDoc["Target Confidence"].isNull()){ - float esp_tconf = metadataDoc["Target Confidence"]; - //debug: - Serial.println("target confidence:"); - Serial.println(esp_tconf); - ////store in preferences - preferences.putFloat("tconf", esp_tconf); - } - //optional: motion alpha, motion beta, stacklight UUID + detector esp_det = get_detector_by_name(endpoint, "door", apiToken); // ESP32-CAM-87E1AC + //error handling detector name doesn't exist + if (strcmp(esp_det.id, "NONE") == 0) { + Serial.println("Error: Detector not found. Try connect to the previous configured detector."); + return; + } + //testing + Serial.println("the id of the esp camera detector is:"); + Serial.println(esp_det.id); + //get det_id: + preferences.putString("det_id", esp_det.id); + strcpy(groundlight_det_id, esp_det.id); + + //deserialize metadata: + String metadataStr = esp_det.metadata; + + DynamicJsonDocument metadataDoc(1024); + + DeserializationError error = deserializeJson(metadataDoc, metadataStr); + + if (error) { + Serial.print(F("deserializeJson() failed: ")); + Serial.println(error.c_str()); + return; } + // from metadata: get query_delay + if (metadataDoc.containsKey("Query Delay (seconds)")) { + query_delay = metadataDoc["Query Delay (seconds)"]; + // + Serial.print(F("Query Delay: ")); + Serial.println(query_delay); + preferences.putInt("query_delay", query_delay); + } else { + Serial.println(F("Query Delay not found in metadata")); + return; + } + //from metadata: get target confidence + if (metadataDoc.containsKey("Target Confidence")) { + targetConfidence = metadataDoc["Target Confidence"];//toFloat()? + // + Serial.print(F("Target Confidence: ")); + Serial.println(targetConfidence); + preferences.putFloat("tConf", targetConfidence); + } else { + Serial.println(F("Query Delay not found in metadata")); + return; + } - // fill it in the form - //saving the form values to preferences, similar to the existing '/config' handling logic + //motion alpha + //motion beta + //SL UUID } -void autosimulation() { - Serial.println("test test test"); - } #endif @@ -462,13 +475,13 @@ void setup() { debug_printf("Firmware : %s built on %s at %s\n", NAME, __DATE__, __TIME__); - xTaskCreate( + xTaskCreate( listener, // Function that should be called "Uart Listener", // Name of the task (for debugging) 10000, // Stack size (bytes) NULL, // Parameter to pass 1, // Task priority - NULL // Task handle + NULL // Task handle ); if (RESET_SETTINGS_GPIO != -1) { @@ -523,18 +536,7 @@ void setup() { }); server.on("/config", HTTP_GET, [] (AsyncWebServerRequest *request) { - //test: - performAutoConfig(request); - - //IF: - //check: run autoconfig or not - if (request->hasParam("ssid", true) && request->hasParam("pw", true) && request->hasParam("api_key", true)) { - performAutoConfig(request); - Serial.println("auto config runs!"); - } - - //ELSE: - preferences.begin("config", false); //can write? + preferences.begin("config", false); if (request->hasParam("ssid") && request->getParam("ssid")->value() != "") { preferences.putString("ssid", request->getParam("ssid")->value()); strcpy(ssid, request->getParam("ssid")->value().c_str()); @@ -543,70 +545,72 @@ void setup() { preferences.putString("password", request->getParam("pw")->value()); strcpy(password, request->getParam("pw")->value().c_str()); } - if (request->hasParam("det_id") && request->getParam("det_id")->value() != "") { - preferences.putString("det_id", request->getParam("det_id")->value()); - strcpy(groundlight_det_id, request->getParam("det_id")->value().c_str()); - } - //request -hasparam check request has the key; request - get param check request has the value; - //pref.putstring: put 'det_id' inside NVS where ssid is key; request ->getparam is value; - //copy value into 'groundlight_get_id" if (request->hasParam("api_key") && request->getParam("api_key")->value() != "") { preferences.putString("api_key", request->getParam("api_key")->value()); strcpy(groundlight_API_key, request->getParam("api_key")->value().c_str()); } - if (request->hasParam("query_delay") && request->getParam("query_delay")->value() != "") { - query_delay = request->getParam("query_delay")->value().toInt(); - preferences.putInt("query_delay", query_delay); - } - if (request->hasParam("endpoint") && request->getParam("endpoint")->value() != "") { - preferences.putString("endpoint", request->getParam("endpoint")->value()); - strcpy(groundlight_endpoint, request->getParam("endpoint")->value().c_str()); - } - if (request->hasParam("tConf") && request->getParam("tConf")->value() != "") { - targetConfidence = request->getParam("tConf")->value().toFloat(); - preferences.putFloat("tConf", targetConfidence); - } - if (request->hasParam("mot_a") && request->getParam("mot_a")->value() != "") { - preferences.putString("mot_a", request->getParam("mot_a")->value()); - } - if (request->hasParam("mot_b") && request->getParam("mot_b")->value() != "") { - preferences.putString("mot_b", request->getParam("mot_b")->value()); - } - if (request->hasParam("sl_uuid") && request->getParam("sl_uuid")->value() != "") { - preferences.putString("sl_uuid", request->getParam("sl_uuid")->value()); - } - if (request->hasParam("slack_url") && request->getParam("slack_url")->value() != "") { - preferences.putString("slack_url", request->getParam("slack_url")->value()); - } - if (request->hasParam("email") && request->getParam("email")->value() != "") { - preferences.putString("email", request->getParam("email")->value()); - } - if (request->hasParam("email_endpoint") && request->getParam("email_endpoint")->value() != "") { - preferences.putString("emailEndpoint", request->getParam("email_endpoint")->value()); - } - if (request->hasParam("email_key") && request->getParam("email_key")->value() != "") { - preferences.putString("emailKey", request->getParam("email_key")->value()); - } - if (request->hasParam("email_host") && request->getParam("email_host")->value() != "") { - preferences.putString("emailHost", request->getParam("email_host")->value()); - } - if (request->hasParam("twilio_sid") && request->getParam("twilio_sid")->value() != "") { - preferences.putString("twilioSID", request->getParam("twilio_sid")->value()); - } - if (request->hasParam("twilio_token") && request->getParam("twilio_token")->value() != "") { - preferences.putString("twilioKey", request->getParam("twilio_token")->value()); - } - if (request->hasParam("twilio_number") && request->getParam("twilio_number")->value() != "") { - preferences.putString("twilioNumber", request->getParam("twilio_number")->value()); - } - if (request->hasParam("twilio_recipient") && request->getParam("twilio_recipient")->value() != "") { - preferences.putString("twilioEndpoint", request->getParam("twilio_recipient")->value()); - } - if (request->hasParam("autoconfig") && request->getParam("autoconfig")->value() != "") { - preferences.putString("autoconfig", request->getParam("autoconfig")->value()); + + if (shouldPerformAutoConfig(request)){ + performAutoConfig(request); + } else { + if (request->hasParam("det_id") && request->getParam("det_id")->value() != "") { + preferences.putString("det_id", request->getParam("det_id")->value()); + strcpy(groundlight_det_id, request->getParam("det_id")->value().c_str()); + } + if (request->hasParam("query_delay") && request->getParam("query_delay")->value() != "") { + query_delay = request->getParam("query_delay")->value().toInt(); + preferences.putInt("query_delay", query_delay); + } + if (request->hasParam("endpoint") && request->getParam("endpoint")->value() != "") { + preferences.putString("endpoint", request->getParam("endpoint")->value()); + strcpy(groundlight_endpoint, request->getParam("endpoint")->value().c_str()); + } + if (request->hasParam("tConf") && request->getParam("tConf")->value() != "") { + targetConfidence = request->getParam("tConf")->value().toFloat(); + preferences.putFloat("tConf", targetConfidence); + } + if (request->hasParam("mot_a") && request->getParam("mot_a")->value() != "") { + preferences.putString("mot_a", request->getParam("mot_a")->value()); + } + if (request->hasParam("mot_b") && request->getParam("mot_b")->value() != "") { + preferences.putString("mot_b", request->getParam("mot_b")->value()); + } + if (request->hasParam("sl_uuid") && request->getParam("sl_uuid")->value() != "") { + preferences.putString("sl_uuid", request->getParam("sl_uuid")->value()); + } + if (request->hasParam("slack_url") && request->getParam("slack_url")->value() != "") { + preferences.putString("slack_url", request->getParam("slack_url")->value()); + } + if (request->hasParam("email") && request->getParam("email")->value() != "") { + preferences.putString("email", request->getParam("email")->value()); + } + if (request->hasParam("email_endpoint") && request->getParam("email_endpoint")->value() != "") { + preferences.putString("emailEndpoint", request->getParam("email_endpoint")->value()); + } + if (request->hasParam("email_key") && request->getParam("email_key")->value() != "") { + preferences.putString("emailKey", request->getParam("email_key")->value()); + } + if (request->hasParam("email_host") && request->getParam("email_host")->value() != "") { + preferences.putString("emailHost", request->getParam("email_host")->value()); + } + if (request->hasParam("twilio_sid") && request->getParam("twilio_sid")->value() != "") { + preferences.putString("twilioSID", request->getParam("twilio_sid")->value()); + } + if (request->hasParam("twilio_token") && request->getParam("twilio_token")->value() != "") { + preferences.putString("twilioKey", request->getParam("twilio_token")->value()); + } + if (request->hasParam("twilio_number") && request->getParam("twilio_number")->value() != "") { + preferences.putString("twilioNumber", request->getParam("twilio_number")->value()); + } + if (request->hasParam("twilio_recipient") && request->getParam("twilio_recipient")->value() != "") { + preferences.putString("twilioEndpoint", request->getParam("twilio_recipient")->value()); + } + if (request->hasParam("autoconfig") && request->getParam("autoconfig")->value() != "") { + preferences.putString("autoconfig", request->getParam("autoconfig")->value()); + } + } - - request->send(200, "text/html", "Configuration sent to your ESP Camera
Return to Home Page"); + // request->send(200, "text/html", "Configuration sent to your ESP Camera
Return to Home Page"); request->send_P(200, "text/html", sent_html); preferences.end(); }); @@ -871,31 +875,16 @@ void loop () { } if (WiFi.isConnected()) { debug_printf("WIFI connected to SSID %s\n", ssid); - //Testing only: - const char* endpoint = "api.groundlight.ai"; - const char* apiToken = API_TOKEN; - String detectors = get_detectors(endpoint, apiToken); - Serial.println(detectors); - //test: - detector_list det_list = get_detector_list(endpoint, apiToken); - Serial.println(det_list.size); //parsing succeeded. - // Check if 'get_detector_by_list' is working: - Serial.println(det_list.detectors[0].id); - - Serial.println(det_list.detectors[0].metadata); //succeeded! - //check if 'get_detector_by_id' is working: - // const char* detector_id = det_list.detectors[0].id; - // detector det = get_detector_by_id(endpoint,detector_id,apiToken); - // Serial.println("get detector by id: "); - // Serial.print(det.name);//succeeded! - //check 'get_detector_by_name': - const char* detectorName = det_list.detectors[0].name; - detector det = get_detector_by_name(endpoint,detectorName,apiToken); - Serial.println("get detector id by name: "); - Serial.print(det.id);//succeeded! - - //deserialize matadata - String metadataString = det_list.detectors[0].metadata; + // //TESTING ONLY: + // const char* endpoint = "api.groundlight.ai"; + // const char* apiToken = API_TOKEN; + // String detectors = get_detectors(endpoint, apiToken); + // Serial.println("detectors string:"); + // Serial.println(detectors); + // const char* detectorName = "cat"; + // detector det = get_detector_by_name(endpoint,detectorName,apiToken); + // Serial.println("get detector id by name: "); + // Serial.print(det.id);//succeeded! } else { From 92db60058b7c00069d975ed5d50a02d168a4836a Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 19 Feb 2024 13:58:24 -0800 Subject: [PATCH 09/28] fixed autoconfig error handling --- src/deployable_example.cpp | 42 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index d884ef2..44d970f 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -397,15 +397,10 @@ void performAutoConfig(AsyncWebServerRequest *request){ Serial.println("Error: Detector not found. Try connect to the previous configured detector."); return; } - //testing - Serial.println("the id of the esp camera detector is:"); - Serial.println(esp_det.id); - //get det_id: - preferences.putString("det_id", esp_det.id); - strcpy(groundlight_det_id, esp_det.id); //deserialize metadata: String metadataStr = esp_det.metadata; + Serial.println(esp_det.metadata); DynamicJsonDocument metadataDoc(1024); @@ -418,33 +413,30 @@ void performAutoConfig(AsyncWebServerRequest *request){ } // from metadata: get query_delay - if (metadataDoc.containsKey("Query Delay (seconds)")) { + if (metadataDoc.containsKey("Query Delay (seconds)") && !metadataDoc["Query Delay (seconds)"].isNull() && metadataDoc.containsKey("Target Confidence") && !metadataDoc["Target Confidence"].isNull()) { + preferences.putString("det_id", esp_det.id); + strcpy(groundlight_det_id, esp_det.id); + query_delay = metadataDoc["Query Delay (seconds)"]; - // + preferences.putInt("query_delay", query_delay); Serial.print(F("Query Delay: ")); Serial.println(query_delay); - preferences.putInt("query_delay", query_delay); - } else { - Serial.println(F("Query Delay not found in metadata")); - return; - } - - //from metadata: get target confidence - if (metadataDoc.containsKey("Target Confidence")) { - targetConfidence = metadataDoc["Target Confidence"];//toFloat()? - // + + targetConfidence = metadataDoc["Target Confidence"]; + preferences.putFloat("tConf", targetConfidence); Serial.print(F("Target Confidence: ")); Serial.println(targetConfidence); - preferences.putFloat("tConf", targetConfidence); + + } else { - Serial.println(F("Query Delay not found in metadata")); + Serial.println(F("Query Delay or Target confidence not found in metadata or no value stored in query delay.")); return; } - - //motion alpha - //motion beta - //SL UUID -} + //optional: + //motion alpha + //motion beta + //SL UUID +} #endif From 4f8577532debd8603a68a9c3b818906da9c7e926 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 19 Feb 2024 15:38:03 -0800 Subject: [PATCH 10/28] set autoconfig to esp detector --- src/deployable_example.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 44d970f..52dce96 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -391,7 +391,7 @@ bool shouldPerformAutoConfig(AsyncWebServerRequest *request) { void performAutoConfig(AsyncWebServerRequest *request){ const char* endpoint = groundlight_endpoint; const char* apiToken = API_TOKEN; - detector esp_det = get_detector_by_name(endpoint, "door", apiToken); // ESP32-CAM-87E1AC + detector esp_det = get_detector_by_name(endpoint, "ESP32-CAM-87E1AC", apiToken); // ESP32-CAM-87E1AC //error handling detector name doesn't exist if (strcmp(esp_det.id, "NONE") == 0) { Serial.println("Error: Detector not found. Try connect to the previous configured detector."); From 2a0a5974a20bae24a5e5066719342acf3fda14c0 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 19 Feb 2024 16:43:56 -0800 Subject: [PATCH 11/28] hide credentials --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 01ee838..2ed8f67 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ src/credentials.h -config/ \ No newline at end of file +config/ + +credentials/ \ No newline at end of file From 0ac74aca4e6f74d777e0d6e7acb5d1825fc23795 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 19 Feb 2024 16:55:03 -0800 Subject: [PATCH 12/28] hide credentials --- .gitignore | 2 -- credentials/api_keys.h | 6 ------ src/deployable_example.cpp | 4 ++-- 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 credentials/api_keys.h diff --git a/.gitignore b/.gitignore index 2ed8f67..0559e82 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,4 @@ src/credentials.h -config/ - credentials/ \ No newline at end of file diff --git a/credentials/api_keys.h b/credentials/api_keys.h deleted file mode 100644 index 99214e3..0000000 --- a/credentials/api_keys.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#define API_TOKEN "api_2apcwsQuXcq8ySCMelpMxdMxmP2_QL2ht1ddZRFaWrfa3QsCHMHtWgeJ5SF9n5"; - -#endif \ No newline at end of file diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 52dce96..2a0aa4a 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -36,7 +36,7 @@ #include "integrations.h" #include "stacklight.h" -#include "../credentials/api_keys.h" //testing only +// #include "../credentials/api_keys.h" //testing only #ifdef PRELOADED_CREDENTIALS #include "credentials.h" @@ -390,7 +390,7 @@ bool shouldPerformAutoConfig(AsyncWebServerRequest *request) { //perform autoconfig: void performAutoConfig(AsyncWebServerRequest *request){ const char* endpoint = groundlight_endpoint; - const char* apiToken = API_TOKEN; + const char* apiToken = groundlight_API_key; detector esp_det = get_detector_by_name(endpoint, "ESP32-CAM-87E1AC", apiToken); // ESP32-CAM-87E1AC //error handling detector name doesn't exist if (strcmp(esp_det.id, "NONE") == 0) { From 1b77c3d12f71a05f82af0fffa1ce1dab80fe3f91 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Wed, 21 Feb 2024 22:00:46 -0800 Subject: [PATCH 13/28] formatted esp form --- src/deployable_example.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 2a0aa4a..8d32509 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -301,11 +301,8 @@ const char index_html[] PROGMEM = R"rawliteral( WiFi SSID: WiFi Password: - API Key: - + API Key: + Autoconfig: Detector Id: Query Delay (seconds): Endpoint: From e15597448ecba2425f079485690c3deb22346a3e Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 22 Feb 2024 13:16:51 -0800 Subject: [PATCH 14/28] fixed autoconfig --- src/deployable_example.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 8d32509..6b8c7f2 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -36,8 +36,6 @@ #include "integrations.h" #include "stacklight.h" -// #include "../credentials/api_keys.h" //testing only - #ifdef PRELOADED_CREDENTIALS #include "credentials.h" #endif @@ -388,8 +386,13 @@ bool shouldPerformAutoConfig(AsyncWebServerRequest *request) { void performAutoConfig(AsyncWebServerRequest *request){ const char* endpoint = groundlight_endpoint; const char* apiToken = groundlight_API_key; - detector esp_det = get_detector_by_name(endpoint, "ESP32-CAM-87E1AC", apiToken); // ESP32-CAM-87E1AC - //error handling detector name doesn't exist + // mac address to detectorName + String mac = WiFi.macAddress(); + mac.replace(":", ""); + mac = mac.substring(6); + String esp_detector_name = (StringSumHelper) "ESP32-CAM-" + mac; + debug_printf("esp cam detector name: %s\n",esp_detector_name.c_str()); + detector esp_det = get_detector_by_name(endpoint, esp_detector_name.c_str(), apiToken); if (strcmp(esp_det.id, "NONE") == 0) { Serial.println("Error: Detector not found. Try connect to the previous configured detector."); return; @@ -397,7 +400,6 @@ void performAutoConfig(AsyncWebServerRequest *request){ //deserialize metadata: String metadataStr = esp_det.metadata; - Serial.println(esp_det.metadata); DynamicJsonDocument metadataDoc(1024); @@ -710,8 +712,7 @@ void setup() { // alloc memory for 565 frames frame_565 = (uint8_t *) ps_malloc(FRAME_ARR_LEN); frame_565_old = (uint8_t *) ps_malloc(FRAME_ARR_LEN); - - debug_printf("detector_id : %s\n",groundlight_det_id); + #ifdef LED_BUILTIN digitalWrite(LED_BUILTIN, LOW); #endif @@ -864,16 +865,6 @@ void loop () { } if (WiFi.isConnected()) { debug_printf("WIFI connected to SSID %s\n", ssid); - // //TESTING ONLY: - // const char* endpoint = "api.groundlight.ai"; - // const char* apiToken = API_TOKEN; - // String detectors = get_detectors(endpoint, apiToken); - // Serial.println("detectors string:"); - // Serial.println(detectors); - // const char* detectorName = "cat"; - // detector det = get_detector_by_name(endpoint,detectorName,apiToken); - // Serial.println("get detector id by name: "); - // Serial.print(det.id);//succeeded! } else { From b4b85fd786bc4bc0f48ca2fd6ec05ccdc83fb18d Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 4 Mar 2024 09:43:27 -0800 Subject: [PATCH 15/28] cleaned up form --- lib/groundlight/src/groundlight.cpp | 10 +++- src/deployable_example.cpp | 74 +++++++++++++++++++---------- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index cb50c93..41135ad 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -437,11 +437,17 @@ detector get_detector_by_id(const char *endpoint, const char *detector_id, const detector get_detector_by_name(const char *endpoint, const char *detectorName, const char *apiToken) { //given input: detectorName detector_list detectors = get_detector_list(endpoint, apiToken); + detector det = { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; for (int i = 0; i < detectors.size; i++) { if (String(detectors.detectors[i].name) == String(detectorName)) { - return detectors.detectors[i]; + det = detectors.detectors[i]; } } - return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; + // return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; + if (0 WiFi Password: API Key: - Autoconfig: + Autoconfig: + Detector Id: Query Delay (seconds): Endpoint: Target Confidence: - Motion Alpha (float between 0 and 1): - Motion Beta (float between 0 and 1): - Stacklight UUID: - Slack URL: - Email: - Email Endpoint: - Email Key: - Email Host: - Twilio SID: - Twilio Token: - Twilio Number: - Twilio Recipient: + Enable Motion Detector: + + Enable Stacklight: + + )rawliteral"; @@ -397,20 +412,15 @@ void performAutoConfig(AsyncWebServerRequest *request){ Serial.println("Error: Detector not found. Try connect to the previous configured detector."); return; } - //deserialize metadata: String metadataStr = esp_det.metadata; - DynamicJsonDocument metadataDoc(1024); - DeserializationError error = deserializeJson(metadataDoc, metadataStr); - if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.c_str()); return; } - // from metadata: get query_delay if (metadataDoc.containsKey("Query Delay (seconds)") && !metadataDoc["Query Delay (seconds)"].isNull() && metadataDoc.containsKey("Target Confidence") && !metadataDoc["Target Confidence"].isNull()) { preferences.putString("det_id", esp_det.id); @@ -426,15 +436,31 @@ void performAutoConfig(AsyncWebServerRequest *request){ Serial.print(F("Target Confidence: ")); Serial.println(targetConfidence); + if (metadataDoc.containsKey("Motion Alpha (float between 0 and 1)") && !metadataDoc["Motion Alpha (float between 0 and 1)"].isNull()){ + String mot_a = metadataDoc["Motion Alpha (float between 0 and 1)"]; + preferences.putString("mot_a",mot_a); + } else { + preferences.remove("mot_a"); + } + if (metadataDoc.containsKey("Motion Beta (float between 0 and 1):") && !metadataDoc["Motion Beta (float between 0 and 1):"].isNull()){ + String mot_b = metadataDoc["Motion Beta (float between 0 and 1):"]; + preferences.putString("mot_b",mot_b); + } else { + preferences.remove("mot_b"); + } + if (metadataDoc.containsKey("Stacklight UUID:") && !metadataDoc["Stacklight UUID:"].isNull()){ + String sl_uuid = metadataDoc["Stacklight UUID:"]; + preferences.putString("sl_uuid",sl_uuid); + Serial.println("we got stacklight UUID"); + } else { + preferences.putString("sl_uuid", " "); + Serial.println("stacklight UUID is empty"); + } } else { Serial.println(F("Query Delay or Target confidence not found in metadata or no value stored in query delay.")); return; } - //optional: - //motion alpha - //motion beta - //SL UUID } #endif From 25884fb553bbc18f1ee01449c14eedcbb47456bc Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 4 Mar 2024 13:36:33 -0800 Subject: [PATCH 16/28] free memory --- .vscode/settings.json | 3 +- lib/groundlight/src/groundlight.cpp | 2 +- src/deployable_example.cpp | 86 ++++++++++++++--------------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 523e4de..a2c40cd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,7 @@ "vector": "cpp", "string_view": "cpp", "initializer_list": "cpp", - "cmath": "cpp" + "cmath": "cpp", + "*.tcc": "cpp" } } \ No newline at end of file diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index 41135ad..818df86 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -445,7 +445,7 @@ detector get_detector_by_name(const char *endpoint, const char *detectorName, co } // return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; if (0 Date: Mon, 4 Mar 2024 13:49:16 -0800 Subject: [PATCH 17/28] more error handling --- src/deployable_example.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 722c60b..8b729f7 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -409,7 +409,8 @@ void performAutoConfig(AsyncWebServerRequest *request){ debug_printf("esp cam detector name: %s\n",esp_detector_name.c_str()); detector esp_det = get_detector_by_name(endpoint, esp_detector_name.c_str(), apiToken); if (strcmp(esp_det.id, "NONE") == 0) { - Serial.println("Error: Detector not found. Try connect to the previous configured detector."); + preferences.putString("det_id", "DETECTOR NOT FOUND"); + Serial.println("Error: Detector not found."); return; } preferences.putString("det_id", esp_det.id); @@ -456,8 +457,7 @@ void performAutoConfig(AsyncWebServerRequest *request){ } else if (metadataDoc.containsKey("Stacklight UUID") && metadataDoc["Stacklight UUID"].isNull()){ preferences.remove("sl_uuid"); } - - } +} #endif From c2edc65db7e3e2103043ead4c57eec53d0518609 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 4 Mar 2024 13:59:36 -0800 Subject: [PATCH 18/28] disabled stacklight --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 8997360..aee8380 100644 --- a/platformio.ini +++ b/platformio.ini @@ -53,6 +53,7 @@ build_flags = '-D CAMERA_MODEL_M5STACK_PSRAM' '-D NAME="GROUNDLIGHT_DEMO_UNIT"' '-D ENABLE_AP' + #'-D ENABLE_STACKLIGHT' lib_deps = ${env.lib_deps} https://github.com/me-no-dev/ESPAsyncWebServer.git#master From f955b197ab79b6b8312d727f14dfecdc60082627 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 4 Mar 2024 15:49:18 -0800 Subject: [PATCH 19/28] cleanup --- .gitignore | 4 +- lib/groundlight/src/groundlight.h | 7 +-- src/deployable_example.cpp | 75 +++++++++++-------------------- 3 files changed, 31 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 0559e82..c52458c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,4 @@ .vscode/ipch .DS_Store -src/credentials.h - -credentials/ \ No newline at end of file +src/credentials.h \ No newline at end of file diff --git a/lib/groundlight/src/groundlight.h b/lib/groundlight/src/groundlight.h index 5161e4f..f7f813e 100644 --- a/lib/groundlight/src/groundlight.h +++ b/lib/groundlight/src/groundlight.h @@ -33,9 +33,9 @@ struct detector char created_at[60]; char name[40]; char query[200]; - char group_name[40]; + char group_name[40]; float confidence_threshold; - char metadata[1024]; // + char metadata[1024]; }; struct detector_list @@ -43,10 +43,11 @@ struct detector_list detector *detectors; uint size; }; + detector_list get_detector_list(const char *endpoint, const char *apiToken); String detector_to_string(detector d); detector get_detector_by_id(const char *endpoint, const char *detectorId, const char *apiToken); -detector get_detector_by_name(const char *endpoint, const char *detectorName, const char *apiToken);// +detector get_detector_by_name(const char *endpoint, const char *detectorName, const char *apiToken); float get_query_confidence(const String &jsonResults); String get_query_id(const String &jsonResults); #endif \ No newline at end of file diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 8b729f7..fe3a5ca 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -1,28 +1,28 @@ -// /* +/* -// Groundlight deployable example of image classification from a visual query. Provided under MIT License below: +Groundlight deployable example of image classification from a visual query. Provided under MIT License below: -// Copyright (c) 2023 Groundlight, Inc. +Copyright (c) 2023 Groundlight, Inc. -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -// */ +*/ #include #include @@ -33,7 +33,7 @@ #include "groundlight.h" #include "camera_pins.h" // thank you seeedstudio for this file -#include "integrations.h" +#include "integrations.h" #include "stacklight.h" #ifdef PRELOADED_CREDENTIALS @@ -169,8 +169,8 @@ int query_delay = 30; // 30 seconds int start_hr = 8; int end_hr = 17; -bool disable_deep_sleep_for_notifications = false; -bool disable_deep_sleep_until_reset = true; //true for testing +bool disable_deep_sleep_for_notifications = false; +bool disable_deep_sleep_until_reset = true; float targetConfidence = 0.9; int retryLimit = 10; @@ -275,10 +275,9 @@ const char index_html[] PROGMEM = R"rawliteral( form { display: flex; flex-direction: column; - /* place-items: center normal; */ - align-items: center; + place-items: center normal; } - input, #motionSettings, #stacklightSettings { + input { width: 80vw; margin: 10px; } @@ -361,7 +360,6 @@ String processor(const String& var) { // String out = String(); String out = ""; // if (var == "ssid") return String(ssid); - // Fetch previously saved data, filled the form chart and store in preference library. if (var == "ssid") out = ssid; else if (var == "password") out = password; else if (var == "det_id") out = groundlight_det_id; @@ -372,22 +370,12 @@ String processor(const String& var) { else if (var == "mot_a" && preferences.isKey("mot_a")) out = String(preferences.getString("mot_a", "0.0")); else if (var == "mot_b" && preferences.isKey("mot_b")) out = String(preferences.getString("mot_b", "0.0")); else if (var == "sl_uuid" && preferences.isKey("sl_uuid")) out = preferences.getString("sl_uuid", ""); - else if (var == "slack_url" && preferences.isKey("slack_url")) out = preferences.getString("slack_url", ""); - else if (var == "email" && preferences.isKey("email")) out = preferences.getString("email", ""); - else if (var == "email_endpoint" && preferences.isKey("emailEndpoint")) out = preferences.getString("emailEndpoint", ""); - else if (var == "email_key" && preferences.isKey("emailKey")) out = preferences.getString("emailKey", ""); - else if (var == "email_host" && preferences.isKey("emailHost")) out = preferences.getString("emailHost", ""); - else if (var == "twilio_sid" && preferences.isKey("twilioSID")) out = preferences.getString("twilioSID", ""); - else if (var == "twilio_token" && preferences.isKey("twilioKey")) out = preferences.getString("twilioKey", ""); - else if (var == "twilio_number" && preferences.isKey("twilioNumber")) out = preferences.getString("twilioNumber", ""); - else if (var == "twilio_recipient" && preferences.isKey("twilioEndpoint")) out = preferences.getString("twilioEndpoint", ""); else if (var == "autoconfig" && preferences.isKey("autoconfig")) out = preferences.getString("autoconfig", ""); preferences.end(); return out; // return var; } -//check if meet autoconfig requirment: bool shouldPerformAutoConfig(AsyncWebServerRequest *request) { bool autoconfigEnabled = request->hasParam("autoconfig"); bool ssidFilled = request->hasParam("ssid") && request->getParam("ssid")->value() != ""; @@ -397,11 +385,9 @@ bool shouldPerformAutoConfig(AsyncWebServerRequest *request) { return autoconfigEnabled && ssidFilled && passwordFilled && apiKeyFilled; } -//perform autoconfig: void performAutoConfig(AsyncWebServerRequest *request){ const char* endpoint = groundlight_endpoint; const char* apiToken = groundlight_API_key; - // mac address to detectorName String mac = WiFi.macAddress(); mac.replace(":", ""); mac = mac.substring(6); @@ -415,7 +401,6 @@ void performAutoConfig(AsyncWebServerRequest *request){ } preferences.putString("det_id", esp_det.id); strcpy(groundlight_det_id, esp_det.id); - //deserialize metadata: String metadataStr = esp_det.metadata; DynamicJsonDocument metadataDoc(1024); DeserializationError error = deserializeJson(metadataDoc, metadataStr); @@ -424,21 +409,14 @@ void performAutoConfig(AsyncWebServerRequest *request){ Serial.println(error.c_str()); return; } - //get parameters from metadata - //if you have query delay: save it . else it's ok if (metadataDoc.containsKey("Query Delay (seconds)") && !metadataDoc["Query Delay (seconds)"].isNull()) { query_delay = metadataDoc["Query Delay (seconds)"]; preferences.putInt("query_delay", query_delay); - // Serial.print(F("Query Delay: ")); - // Serial.println(query_delay); } if (metadataDoc.containsKey("Target Confidence") && !metadataDoc["Target Confidence"].isNull()) { targetConfidence = metadataDoc["Target Confidence"]; preferences.putFloat("tConf", targetConfidence); - // Serial.print(F("Target Confidence: ")); - // Serial.println(targetConfidence); } - //if metadata doesn't have below parameter, we disable default settings: if (metadataDoc.containsKey("Motion Alpha (float between 0 and 1)") && !metadataDoc["Motion Alpha (float between 0 and 1)"].isNull()){ String mot_a = metadataDoc["Motion Alpha (float between 0 and 1)"]; preferences.putString("mot_a",mot_a); @@ -458,7 +436,6 @@ void performAutoConfig(AsyncWebServerRequest *request){ preferences.remove("sl_uuid"); } } - #endif void setup() { @@ -488,13 +465,13 @@ void setup() { debug_printf("Firmware : %s built on %s at %s\n", NAME, __DATE__, __TIME__); - xTaskCreate( + xTaskCreate( listener, // Function that should be called "Uart Listener", // Name of the task (for debugging) 10000, // Stack size (bytes) NULL, // Parameter to pass 1, // Task priority - NULL // Task handle + NULL // Task handle ); if (RESET_SETTINGS_GPIO != -1) { From faff733ca111b95615e921457cf22e5faa963c05 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 4 Mar 2024 16:38:56 -0800 Subject: [PATCH 20/28] more cleanup --- lib/groundlight/src/groundlight.cpp | 35 +++++++++++++---------------- platformio.ini | 2 +- src/deployable_example.cpp | 33 +++------------------------ 3 files changed, 19 insertions(+), 51 deletions(-) diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index 818df86..2786c66 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -355,11 +355,9 @@ String get_query_id(const String &jsonResults) { DynamicJsonDocument results(1024); ArduinoJson::DeserializationError deserializeError = deserializeJson(results, jsonResults); if (deserializeError != ArduinoJson::DeserializationError::Ok) { - // Serial.println("Failed to parse JSON"); return "NONE"; } if (!results.containsKey("id")) { - // Serial.println("No query ID found in JSON"); return "NONE"; } return results["id"]; @@ -367,38 +365,32 @@ String get_query_id(const String &jsonResults) { StaticJsonDocument groundlight_json_doc; -// Parses the detectors from the Groundlight API. detector_list get_detector_list(const char *endpoint, const char *apiToken) { String jsonResponse = get_detectors(endpoint, apiToken); - // deserializeJson(groundlight_json_doc, get_detectors(endpoint, apiToken)); - //debug parsing: auto error = deserializeJson(groundlight_json_doc, jsonResponse); if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); - return {}; // Return an empty detector_list if parsing fails + return {}; } - //if it is not empty: - JsonArray detectors = groundlight_json_doc["results"]; //json -> array + JsonArray detectors = groundlight_json_doc["results"]; detector *_detector_list = new detector[detectors.size()]; for (int i = 0; i < detectors.size(); i++) { - JsonObject detectorObj = detectors[i]; //detector - - _detector_list[i].confidence_threshold = detectors[i]["confidence_threshold"]; //float or str? + JsonObject detectorObj = detectors[i]; + _detector_list[i].confidence_threshold = detectors[i]["confidence_threshold"]; strcpy(_detector_list[i].id, detectors[i]["id"]); strcpy(_detector_list[i].type, detectors[i]["type"]); strcpy(_detector_list[i].created_at, detectors[i]["created_at"]); strcpy(_detector_list[i].name, detectors[i]["name"]); strcpy(_detector_list[i].query, detectors[i]["query"]); strcpy(_detector_list[i].group_name, detectors[i]["group_name"]); - // serialize and copy metadata if (!detectorObj["metadata"].isNull()) { String metadataStr; serializeJson(detectorObj["metadata"], metadataStr); strlcpy(_detector_list[i].metadata, metadataStr.c_str(), sizeof(_detector_list[i].metadata)); } else { - _detector_list[i].metadata[0] = '\0'; //set to an empty string if metadata is null. + _detector_list[i].metadata[0] = '\0'; } } detector_list res = { _detector_list, detectors.size() }; @@ -420,22 +412,26 @@ String detector_to_string(detector d) { res += d.group_name; res += "\n\tConfidence threshold: "; res += d.confidence_threshold; - res += "\n\tMetadata: "; //added metadata + res += "\n\tMetadata: "; res += d.metadata; return res; } -detector get_detector_by_id(const char *endpoint, const char *detector_id, const char *apiToken) { +detector get_detector_by_id(const char *endpoint, const char *detectorId, const char *apiToken) { detector_list detectors = get_detector_list(endpoint, apiToken); + detector det = { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; for (int i = 0; i < detectors.size; i++) { - if (String(detectors.detectors[i].id) == String(detector_id)) { - return detectors.detectors[i]; + if (String(detectors.detectors[i].id) == String(detectorId)) { + det = detectors.detectors[i]; } } - return detector { "NONE", "NONE", "NONE", "NONE", "NONE", "NONE", 0.0, "None" }; + if (0send_P(200, "text/html", index_html, processor); + request->send_P(200, "text/html", index_html, processor); }); server.on("/config", HTTP_GET, [] (AsyncWebServerRequest *request) { - preferences.begin("config", false); + preferences.begin("config", false); if (request->hasParam("ssid") && request->getParam("ssid")->value() != "") { preferences.putString("ssid", request->getParam("ssid")->value()); strcpy(ssid, request->getParam("ssid")->value().c_str()); - } + } if (request->hasParam("pw") && request->getParam("pw")->value() != "") { preferences.putString("password", request->getParam("pw")->value()); strcpy(password, request->getParam("pw")->value().c_str()); @@ -568,33 +568,6 @@ void setup() { if (request->hasParam("sl_uuid") && request->getParam("sl_uuid")->value() != "") { preferences.putString("sl_uuid", request->getParam("sl_uuid")->value()); } - if (request->hasParam("slack_url") && request->getParam("slack_url")->value() != "") { - preferences.putString("slack_url", request->getParam("slack_url")->value()); - } - if (request->hasParam("email") && request->getParam("email")->value() != "") { - preferences.putString("email", request->getParam("email")->value()); - } - if (request->hasParam("email_endpoint") && request->getParam("email_endpoint")->value() != "") { - preferences.putString("emailEndpoint", request->getParam("email_endpoint")->value()); - } - if (request->hasParam("email_key") && request->getParam("email_key")->value() != "") { - preferences.putString("emailKey", request->getParam("email_key")->value()); - } - if (request->hasParam("email_host") && request->getParam("email_host")->value() != "") { - preferences.putString("emailHost", request->getParam("email_host")->value()); - } - if (request->hasParam("twilio_sid") && request->getParam("twilio_sid")->value() != "") { - preferences.putString("twilioSID", request->getParam("twilio_sid")->value()); - } - if (request->hasParam("twilio_token") && request->getParam("twilio_token")->value() != "") { - preferences.putString("twilioKey", request->getParam("twilio_token")->value()); - } - if (request->hasParam("twilio_number") && request->getParam("twilio_number")->value() != "") { - preferences.putString("twilioNumber", request->getParam("twilio_number")->value()); - } - if (request->hasParam("twilio_recipient") && request->getParam("twilio_recipient")->value() != "") { - preferences.putString("twilioEndpoint", request->getParam("twilio_recipient")->value()); - } if (request->hasParam("autoconfig") && request->getParam("autoconfig")->value() != "") { preferences.putString("autoconfig", request->getParam("autoconfig")->value()); } From 622f25e1b408c9a72f9a74ae6596f75462e2ce07 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 4 Mar 2024 16:56:10 -0800 Subject: [PATCH 21/28] cleanup --- lib/groundlight/src/groundlight.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index 2786c66..d5eddb5 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -367,12 +367,7 @@ StaticJsonDocument groundlight_json_doc; detector_list get_detector_list(const char *endpoint, const char *apiToken) { String jsonResponse = get_detectors(endpoint, apiToken); - auto error = deserializeJson(groundlight_json_doc, jsonResponse); - if (error) { - Serial.print("deserializeJson() failed: "); - Serial.println(error.c_str()); - return {}; - } + deserializeJson(groundlight_json_doc, jsonResponse); JsonArray detectors = groundlight_json_doc["results"]; detector *_detector_list = new detector[detectors.size()]; for (int i = 0; i < detectors.size(); i++) From 36a23544754455a3b808499c6c5d3e34efe647a9 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Sun, 10 Mar 2024 19:19:53 -0700 Subject: [PATCH 22/28] more cleanup --- lib/groundlight/src/groundlight.cpp | 10 +++++----- src/deployable_example.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index d5eddb5..3d3e3c7 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -355,9 +355,11 @@ String get_query_id(const String &jsonResults) { DynamicJsonDocument results(1024); ArduinoJson::DeserializationError deserializeError = deserializeJson(results, jsonResults); if (deserializeError != ArduinoJson::DeserializationError::Ok) { + // Serial.println("Failed to parse JSON"); return "NONE"; } if (!results.containsKey("id")) { + // Serial.println("No query ID found in JSON"); return "NONE"; } return results["id"]; @@ -366,13 +368,11 @@ String get_query_id(const String &jsonResults) { StaticJsonDocument groundlight_json_doc; detector_list get_detector_list(const char *endpoint, const char *apiToken) { - String jsonResponse = get_detectors(endpoint, apiToken); - deserializeJson(groundlight_json_doc, jsonResponse); + deserializeJson(groundlight_json_doc, get_detectors(endpoint, apiToken)); JsonArray detectors = groundlight_json_doc["results"]; detector *_detector_list = new detector[detectors.size()]; for (int i = 0; i < detectors.size(); i++) { - JsonObject detectorObj = detectors[i]; _detector_list[i].confidence_threshold = detectors[i]["confidence_threshold"]; strcpy(_detector_list[i].id, detectors[i]["id"]); strcpy(_detector_list[i].type, detectors[i]["type"]); @@ -380,9 +380,9 @@ detector_list get_detector_list(const char *endpoint, const char *apiToken) { strcpy(_detector_list[i].name, detectors[i]["name"]); strcpy(_detector_list[i].query, detectors[i]["query"]); strcpy(_detector_list[i].group_name, detectors[i]["group_name"]); - if (!detectorObj["metadata"].isNull()) { + if (!detectors[i]["metadata"].isNull()) { String metadataStr; - serializeJson(detectorObj["metadata"], metadataStr); + serializeJson(detectors[i]["metadata"], metadataStr); strlcpy(_detector_list[i].metadata, metadataStr.c_str(), sizeof(_detector_list[i].metadata)); } else { _detector_list[i].metadata[0] = '\0'; diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index b03c1cb..485d44e 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -523,7 +523,7 @@ void setup() { // at http://192.168.4.1/ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/html", index_html, processor); - }); + }); server.on("/config", HTTP_GET, [] (AsyncWebServerRequest *request) { preferences.begin("config", false); From 8541346b1facb94d4c6b43208ba23afbcadd3720 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 14 Mar 2024 10:56:04 -0700 Subject: [PATCH 23/28] whitespace cleanup, and corrected .vscode/settings --- .vscode/settings.json | 3 +-- lib/groundlight/src/groundlight.cpp | 2 +- src/deployable_example.cpp | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a2c40cd..523e4de 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,6 @@ "vector": "cpp", "string_view": "cpp", "initializer_list": "cpp", - "cmath": "cpp", - "*.tcc": "cpp" + "cmath": "cpp" } } \ No newline at end of file diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index 3d3e3c7..b13fa70 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -378,7 +378,7 @@ detector_list get_detector_list(const char *endpoint, const char *apiToken) { strcpy(_detector_list[i].type, detectors[i]["type"]); strcpy(_detector_list[i].created_at, detectors[i]["created_at"]); strcpy(_detector_list[i].name, detectors[i]["name"]); - strcpy(_detector_list[i].query, detectors[i]["query"]); + strlcpy(_detector_list[i].query, detectors[i]["query"],sizeof(_detector_list[i].query)); strcpy(_detector_list[i].group_name, detectors[i]["group_name"]); if (!detectors[i]["metadata"].isNull()) { String metadataStr; diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 485d44e..7dc8d7b 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -838,7 +838,6 @@ void loop () { } if (WiFi.isConnected()) { debug_printf("WIFI connected to SSID %s\n", ssid); - } else { debug_printf("unable to connect to wifi status code %d! (skipping image query and looping again)\n", WiFi.status()); @@ -1232,8 +1231,10 @@ bool notifyStacklight(const char * label) { stacklightState = STACKLIGHT_ONLINE; String SSID = ((const StringSumHelper)"GL_STACKLIGHT_" + preferences.getString("sl_uuid", "")); WiFi.begin(SSID, (const StringSumHelper)"gl_stacklight_password_" + preferences.getString("sl_uuid", "")); + Serial.println("wifi begins"); for (int i = 0; i < 40 && WiFi.status() != WL_CONNECTED; i++) { vTaskDelay(500 / portTICK_PERIOD_MS); + Serial.println("debug"); } if(WiFi.isConnected()) { String res = Stacklight::tryConnectToStacklight(ssid, password); From bc3959b3debf4b3acfb1aaefb6e8dc50cacc8e69 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Thu, 14 Mar 2024 11:13:51 -0700 Subject: [PATCH 24/28] clean up comments --- lib/groundlight/src/groundlight.cpp | 2 +- src/deployable_example.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index b13fa70..3d3e3c7 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -378,7 +378,7 @@ detector_list get_detector_list(const char *endpoint, const char *apiToken) { strcpy(_detector_list[i].type, detectors[i]["type"]); strcpy(_detector_list[i].created_at, detectors[i]["created_at"]); strcpy(_detector_list[i].name, detectors[i]["name"]); - strlcpy(_detector_list[i].query, detectors[i]["query"],sizeof(_detector_list[i].query)); + strcpy(_detector_list[i].query, detectors[i]["query"]); strcpy(_detector_list[i].group_name, detectors[i]["group_name"]); if (!detectors[i]["metadata"].isNull()) { String metadataStr; diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 7dc8d7b..89eace7 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -1231,10 +1231,8 @@ bool notifyStacklight(const char * label) { stacklightState = STACKLIGHT_ONLINE; String SSID = ((const StringSumHelper)"GL_STACKLIGHT_" + preferences.getString("sl_uuid", "")); WiFi.begin(SSID, (const StringSumHelper)"gl_stacklight_password_" + preferences.getString("sl_uuid", "")); - Serial.println("wifi begins"); for (int i = 0; i < 40 && WiFi.status() != WL_CONNECTED; i++) { vTaskDelay(500 / portTICK_PERIOD_MS); - Serial.println("debug"); } if(WiFi.isConnected()) { String res = Stacklight::tryConnectToStacklight(ssid, password); From 40dff6924e3fcaf8cb8b36f64aa2a11071510054 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Fri, 15 Mar 2024 13:40:01 -0700 Subject: [PATCH 25/28] cleanup preferences storage --- src/deployable_example.cpp | 46 -------------------------------------- 1 file changed, 46 deletions(-) diff --git a/src/deployable_example.cpp b/src/deployable_example.cpp index 89eace7..8bea36a 100644 --- a/src/deployable_example.cpp +++ b/src/deployable_example.cpp @@ -1011,36 +1011,6 @@ bool try_save_config(char * input) { } else { preferences.remove("endpoint"); } - if (doc["additional_config"].containsKey("notificationOptions") && doc["additional_config"]["notificationOptions"] != "None") { - debug_println("Found notification options!"); - preferences.putString("notiOptns", (const char *)doc["additional_config"]["notificationOptions"]); - if (doc["additional_config"].containsKey("slack") && doc["additional_config"]["slack"].containsKey("slackKey")) { - debug_println("Found slack!"); - preferences.putString("slackKey", (const char *)doc["additional_config"]["slack"]["slackKey"]); - preferences.putString("slackEndpoint", (const char *)doc["additional_config"]["slack"]["slackEndpoint"]); - } else { - preferences.remove("slackKey"); - preferences.remove("slackEndpoint"); - } - if (doc["additional_config"].containsKey("twilio") && doc["additional_config"]["twilio"].containsKey("twilioKey")) { - debug_println("Found twilio!"); - preferences.putString("twilioSID", (const char *)doc["additional_config"]["twilio"]["twilioSID"]); - preferences.putString("twilioKey", (const char *)doc["additional_config"]["twilio"]["twilioKey"]); - preferences.putString("twilioNumber", (const char *)doc["additional_config"]["twilio"]["twilioNumber"]); - preferences.putString("twilioEndpoint", (const char *)doc["additional_config"]["twilio"]["twilioEndpoint"]); - } else { - preferences.remove("twilioKey"); - } - if (doc["additional_config"].containsKey("email") && doc["additional_config"]["email"].containsKey("emailKey")) { - debug_println("Found email!"); - preferences.putString("emailKey", (const char *)doc["additional_config"]["email"]["emailKey"]); - preferences.putString("emailEndpoint", (const char *)doc["additional_config"]["email"]["emailEndpoint"]); - preferences.putString("email", (const char *)doc["additional_config"]["email"]["email"]); - preferences.putString("emailHost", (const char *)doc["additional_config"]["email"]["emailHost"]); - } else { - preferences.remove("emailKey"); - } - } if (doc["additional_config"].containsKey("stacklight") && doc["additional_config"]["stacklight"].containsKey("uuid")) { debug_println("Found stacklight!"); preferences.putString("sl_uuid", (const char *)doc["additional_config"]["stacklight"]["uuid"]); @@ -1301,22 +1271,6 @@ void try_answer_query(String input) { if (preferences.isKey("notiOptns")) { synthesisDoc["additional_config"]["notificationOptions"] = preferences.getString("notiOptns", "None"); } - if (preferences.isKey("slackKey") && preferences.isKey("slackEndpoint")) { - synthesisDoc["additional_config"]["slack"]["slackKey"] = preferences.getString("slackKey", "None"); - synthesisDoc["additional_config"]["slack"]["slackEndpoint"] = preferences.getString("slackEndpoint", "None"); - } - if (preferences.isKey("twilioSID") && preferences.isKey("twilioKey") && preferences.isKey("twilioNumber") && preferences.isKey("twilioEndpoint")) { - synthesisDoc["additional_config"]["twilio"]["twilioSID"] = preferences.getString("twilioSID", "None"); - synthesisDoc["additional_config"]["twilio"]["twilioKey"] = preferences.getString("twilioKey", "None"); - synthesisDoc["additional_config"]["twilio"]["twilioNumber"] = preferences.getString("twilioNumber", "None"); - synthesisDoc["additional_config"]["twilio"]["twilioEndpoint"] = preferences.getString("twilioEndpoint", "None"); - } - if (preferences.isKey("emailKey") && preferences.isKey("email") && preferences.isKey("emailEndpoint")) { - synthesisDoc["additional_config"]["email"]["emailKey"] = preferences.getString("emailKey", "None"); - synthesisDoc["additional_config"]["email"]["emailEndpoint"] = preferences.getString("emailEndpoint", "None"); - synthesisDoc["additional_config"]["email"]["email"] = preferences.getString("email", "None"); - synthesisDoc["additional_config"]["email"]["emailHost"] = preferences.getString("emailHost", "None"); - } if (preferences.isKey("sl_uuid")) { synthesisDoc["additional_config"]["stacklight"]["uuid"] = preferences.getString("sl_uuid", "None"); if (preferences.isKey("sl_switch")) { From 3400ef8a0c89ba9bf7f84e84feacc9cc22820093 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 18 Mar 2024 14:38:21 -0700 Subject: [PATCH 26/28] fixed local web form --- lib/groundlight/src/groundlight.cpp | 13 ++++--- src/deployable_example.cpp | 59 ++++++++++++++++------------- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/lib/groundlight/src/groundlight.cpp b/lib/groundlight/src/groundlight.cpp index 3d3e3c7..a931c28 100644 --- a/lib/groundlight/src/groundlight.cpp +++ b/lib/groundlight/src/groundlight.cpp @@ -374,12 +374,12 @@ detector_list get_detector_list(const char *endpoint, const char *apiToken) { for (int i = 0; i < detectors.size(); i++) { _detector_list[i].confidence_threshold = detectors[i]["confidence_threshold"]; - strcpy(_detector_list[i].id, detectors[i]["id"]); - strcpy(_detector_list[i].type, detectors[i]["type"]); - strcpy(_detector_list[i].created_at, detectors[i]["created_at"]); - strcpy(_detector_list[i].name, detectors[i]["name"]); - strcpy(_detector_list[i].query, detectors[i]["query"]); - strcpy(_detector_list[i].group_name, detectors[i]["group_name"]); + strlcpy(_detector_list[i].id, detectors[i]["id"], sizeof(_detector_list[i].id)); + strlcpy(_detector_list[i].type, detectors[i]["type"], sizeof(_detector_list[i].type)); + strlcpy(_detector_list[i].created_at, detectors[i]["created_at"], sizeof((_detector_list[i].created_at))); + strlcpy(_detector_list[i].name, detectors[i]["name"], sizeof(_detector_list[i].name)); + strlcpy(_detector_list[i].query, detectors[i]["query"], sizeof(_detector_list[i].query)); + strlcpy(_detector_list[i].group_name, detectors[i]["group_name"], sizeof(_detector_list[i].group_name)); if (!detectors[i]["metadata"].isNull()) { String metadataStr; serializeJson(detectors[i]["metadata"], metadataStr); @@ -418,6 +418,7 @@ detector get_detector_by_id(const char *endpoint, const char *detectorId, const for (int i = 0; i < detectors.size; i++) { if (String(detectors.detectors[i].id) == String(detectorId)) { det = detectors.detectors[i]; + break; } } if (0 - -
- WiFi SSID: - WiFi Password: - API Key: - Autoconfig: - - Detector Id: - Query Delay (seconds): - Endpoint: - Target Confidence: - Enable Motion Detector: - - Enable Stacklight: - - -
+ +
+ WiFi SSID: + WiFi Password: + API Key: + Autoconfig: + + Detector Id: + Query Delay (seconds): + Endpoint: + Target Confidence: )rawliteral" + #ifdef ENABLE_STACKLIGHT + R"rawliteral( + Enable Motion Detector: + + Enable Stacklight: + + )rawliteral" + #else + #endif + R"rawliteral( +
)rawliteral"; @@ -396,7 +401,7 @@ void performAutoConfig(AsyncWebServerRequest *request){ detector esp_det = get_detector_by_name(endpoint, esp_detector_name.c_str(), apiToken); if (strcmp(esp_det.id, "NONE") == 0) { preferences.putString("det_id", "DETECTOR NOT FOUND"); - Serial.println("Error: Detector not found."); + debug_printf("Error: Detector not found."); return; } preferences.putString("det_id", esp_det.id); @@ -405,8 +410,8 @@ void performAutoConfig(AsyncWebServerRequest *request){ DynamicJsonDocument metadataDoc(1024); DeserializationError error = deserializeJson(metadataDoc, metadataStr); if (error) { - Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.c_str()); + debug_printf(("deserializeJson() failed: ")); + debug_printf(error.c_str()); return; } if (metadataDoc.containsKey("Query Delay (seconds)") && !metadataDoc["Query Delay (seconds)"].isNull()) { From 8c76559cc1e451450628c09e5733db0f9f6cead6 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 18 Mar 2024 15:11:57 -0700 Subject: [PATCH 27/28] solve platformio.ini conflict --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 531c2d8..33537d7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -53,7 +53,7 @@ build_flags = '-D CAMERA_MODEL_M5STACK_PSRAM' '-D NAME="GROUNDLIGHT_DEMO_UNIT"' '-D ENABLE_AP' -# '-D ENABLE_STACKLIGHT' + '-D ENABLE_STACKLIGHT' lib_deps = ${env.lib_deps} https://github.com/me-no-dev/ESPAsyncWebServer.git#master From 94bb46293301ca39bba0ba5297ba9d361b640d86 Mon Sep 17 00:00:00 2001 From: Supersilvia Date: Mon, 18 Mar 2024 15:13:32 -0700 Subject: [PATCH 28/28] deactivate enable_stacklight --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 33537d7..531c2d8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -53,7 +53,7 @@ build_flags = '-D CAMERA_MODEL_M5STACK_PSRAM' '-D NAME="GROUNDLIGHT_DEMO_UNIT"' '-D ENABLE_AP' - '-D ENABLE_STACKLIGHT' +# '-D ENABLE_STACKLIGHT' lib_deps = ${env.lib_deps} https://github.com/me-no-dev/ESPAsyncWebServer.git#master