Skip to content

Commit 62e6139

Browse files
committed
Merge branch 'v3_develop' of github.com:luxonis/depthai-core into v3_develop
2 parents ffc3ab0 + f5bd0dd commit 62e6139

File tree

9 files changed

+97
-79
lines changed

9 files changed

+97
-79
lines changed

CMakeLists.txt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ option(DEPTHAI_NEW_FIND_PYTHON "Use new FindPython module" ON)
1717
if(NOT DEPTHAI_OPENCV_SUPPORT)
1818
set(DEPTHAI_MERGED_TARGET OFF CACHE BOOL "Enable merged target build" FORCE)
1919
endif()
20-
option(DEPTHAI_ENABLE_EVENTS_MANAGER "Enable Events Manager" ON)
2120

2221
set(DEPTHAI_HAS_APRIL_TAG ${DEPTHAI_ENABLE_APRIL_TAG})
2322
if(WIN32)
@@ -108,18 +107,17 @@ endif()
108107

109108
if(DEPTHAI_ENABLE_PROTOBUF)
110109
option(DEPTHAI_ENABLE_REMOTE_CONNECTION "Enable Remote Connection support" ON)
110+
if(DEPTHAI_ENABLE_CURL)
111+
option(DEPTHAI_ENABLE_EVENTS_MANAGER "Enable Events Manager" ON)
112+
else()
113+
message(STATUS "Events Manager disabled because Protobuf & curl support is disabled.")
114+
option(DEPTHAI_ENABLE_EVENTS_MANAGER "Enable Events Manager" OFF)
115+
endif()
111116
else()
112117
option(DEPTHAI_ENABLE_REMOTE_CONNECTION "Enable Remote Connection support" OFF)
113118
message(STATUS "Remote Connection support disabled because Protobuf support is disabled.")
114119
endif()
115120

116-
if(DEPTHAI_ENABLE_EVENTS_MANAGER)
117-
if(NOT DEPTHAI_ENABLE_PROTOBUF OR NOT DEPTHAI_CURL_SUPPORT)
118-
message(STATUS "Events Manager disabled because Protobuf & curl support is disabled.")
119-
set(DEPTHAI_ENABLE_EVENTS_MANAGER OFF)
120-
endif()
121-
endif()
122-
123121
if(DEPTHAI_BUILD_PYTHON)
124122
list(APPEND VCPKG_MANIFEST_FEATURES "python-bindings")
125123
endif()

examples/cpp/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ dai_add_example(model_zoo RVC2/ModelZoo/model_zoo.cpp OFF OFF)
286286

287287
# Events Manager
288288
if(DEPTHAI_ENABLE_EVENTS_MANAGER)
289-
dai_add_example(events HostNodes/events.cpp ON OFF)
289+
dai_add_example(events Events/events.cpp ON OFF)
290290
endif()
291291
# Image Align
292292
dai_add_example(image_align RVC2/ImageAlign/image_align.cpp OFF OFF)

examples/cpp/HostNodes/events.cpp renamed to examples/cpp/Events/events.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#include <chrono>
32
#include <iostream>
43
#include <string>
@@ -27,20 +26,6 @@ int main(int argc, char* argv[]) {
2726
std::vector<std::shared_ptr<dai::utility::EventData>> data;
2827
data.emplace_back(fileData);
2928
eventsManager->sendEvent("testdata", nullptr, data, {"tag3", "tag4"}, {{"key8", "value8"}});
30-
auto fileData2 = std::make_shared<dai::utility::EventData>("/test.txt");
31-
std::vector<std::shared_ptr<dai::utility::EventData>> data2;
32-
data2.push_back(fileData2);
33-
// will fail, you sendEvent instead of sendSnap
34-
eventsManager->sendSnap("testdata2", nullptr, data2, {"tag5", "tag6"}, {{"key8", "value8"}});
35-
auto fileData3 = std::make_shared<dai::utility::EventData>("/test.jpg");
36-
std::vector<std::shared_ptr<dai::utility::EventData>> data3;
37-
data3.push_back(fileData3);
38-
eventsManager->sendSnap("testdata3", nullptr, data3, {"tag7", "tag8"}, {{"key8", "value8"}});
39-
std::vector<std::shared_ptr<dai::utility::EventData>> data4;
40-
data4.push_back(fileData);
41-
data4.push_back(fileData2);
42-
eventsManager->sendEvent("testdata4", nullptr, data4, {"tag9", "tag10"}, {{"key8", "value8"}});
43-
data4.push_back(fileData3);
4429
while(pipeline.isRunning()) {
4530
auto rgb = previewQ->get<dai::ImgFrame>();
4631

@@ -49,10 +34,6 @@ int main(int argc, char* argv[]) {
4934

5035
if(!sent) {
5136
eventsManager->sendSnap("rgb", rgb, {}, {"tag11", "tag12"}, {{"key", "value"}});
52-
// will fail due to two images being sent, use sendEvent instead
53-
eventsManager->sendSnap("test2", rgb, data3, {"tag13", "tag14"}, {{"key8", "value8"}});
54-
// will fail, sendSnap requires only one image data to be present
55-
eventsManager->sendSnap("test3", rgb, data4, {"tag13", "tag14"}, {{"key8", "value8"}});
5637
sent = true;
5738
}
5839
//

examples/python/HostNodes/events.py renamed to examples/python/Events/events.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#!/usr/bin/env python3
32

43
import cv2
@@ -10,7 +9,7 @@
109
# Create pipeline
1110
with dai.Pipeline() as pipeline:
1211
# Define sources and outputs
13-
camRgb = pipeline.create(dai.node.Camera)
12+
camRgb = pipeline.create(dai.node.Camera).build()
1413
# Properties
1514

1615
qRgb = camRgb.requestOutput((256,256)).createOutputQueue()
@@ -22,10 +21,6 @@
2221
time.sleep(2)
2322
fileData = dai.EventData(b'Hello, world!', "hello.txt", "text/plain")
2423
eventMan.sendEvent("test2", None, [fileData], ["tag1", "tag2"], {"key1": "value1"})
25-
fileData2 = dai.EventData("/test.txt")
26-
# will fail, sendSnap needs an image
27-
eventMan.sendSnap("test3", None, [fileData2], ["tag1", "tag2"], {"key1": "value1"})
28-
eventMan.sendEvent("test4", None, [fileData, fileData2], ["tag1", "tag2"], {"key1": "value1"})
2924
pipeline.start()
3025

3126
frame = None
@@ -39,8 +34,6 @@
3934
frame = inRgb.getCvFrame()
4035
if not eventSent:
4136
eventMan.sendSnap("rgb", inRgb, [], ["tag1", "tag2"], {"key1": "value1"})
42-
# will fail, sendSnap requires only image and no extra data
43-
eventMan.sendSnap("rgb2", inRgb, [fileData2], ["tag1", "tag2"], {"key1": "value1"})
4437
eventSent = True
4538

4639
if frame is not None:

include/depthai/modelzoo/NNModelDescription.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct NNModelDescription {
5454
/** SNPE version = OPTIONAL parameter */
5555
std::string snpeVersion;
5656

57-
/** modelPrecisionType */
57+
/** modelPrecisionType = OPTIONAL parameter */
5858
std::string modelPrecisionType;
5959
};
6060

include/depthai/modelzoo/Zoo.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "depthai/modelzoo/NNModelDescription.hpp"
44

55
namespace dai {
6-
constexpr const char* MODEL_ZOO_URL = "https://api.cloud.luxonis.com/graphql";
6+
constexpr const char* MODEL_ZOO_URL = "https://easyml.cloud.luxonis.com/models/api/v1/models/download";
77
constexpr const char* MODEL_ZOO_DEFAULT_CACHE_DIRECTORY = ".depthai_cached_models";
88

99
/**

include/depthai/utility/EventsManager.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <condition_variable>
34
#include <memory>
45
#include <mutex>
56
#include <string>
@@ -19,7 +20,6 @@ class Event;
1920
} // namespace event
2021
} // namespace proto
2122
namespace utility {
22-
#ifdef DEPTHAI_ENABLE_PROTOBUF
2323
enum class EventDataType { DATA, FILE_URL, IMG_FRAME, ENCODED_FRAME, NN_DATA };
2424
class EventData {
2525
public:
@@ -172,7 +172,9 @@ class EventsManager {
172172
std::string cacheDir;
173173
bool uploadCachedOnStart;
174174
bool cacheIfCannotSend;
175+
std::atomic<bool> stopEventBuffer;
176+
std::condition_variable eventBufferCondition;
177+
std::mutex eventBufferConditionMutex;
175178
};
176-
#endif
177179
} // namespace utility
178180
} // namespace dai

src/modelzoo/Zoo.cpp

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
#include "utility/Logging.hpp"
1010

1111
#ifdef DEPTHAI_ENABLE_CURL
12-
#include <cpr/cpr.h>
12+
#include <cpr/api.h>
13+
#include <cpr/parameters.h>
14+
#include <cpr/status_codes.h>
1315
namespace dai {
1416
class ZooManager {
1517
public:
@@ -139,10 +141,10 @@ bool checkIsErrorHub(const cpr::Response& response) {
139141
// Check if response is an HTTP error
140142
if(response.status_code != cpr::status::HTTP_OK) return true;
141143

142-
// If there was no HTTP error, check response content for errors
144+
// If there was no HTTP error, check presence of required fields
143145
nlohmann::json responseJson = nlohmann::json::parse(response.text);
144-
if(responseJson.contains("errors")) return true;
145-
if(responseJson["data"]["ml"]["modelDownloads"].is_null()) return true;
146+
if(!responseJson.contains("hash")) return true;
147+
if(!responseJson.contains("download_links")) return true;
146148

147149
// All checks passed - no errors yay
148150
return false;
@@ -206,47 +208,53 @@ bool ZooManager::isModelCached() const {
206208
}
207209

208210
void ZooManager::downloadModel() {
209-
// graphql query to send to Hub - always the same
210-
constexpr std::string_view MODEL_ZOO_QUERY = "query MlDownloads($input: MlModelDownloadsInput!) {ml { modelDownloads(input : $input) { data }}}";
211-
212-
// Setup request body
213-
nlohmann::json requestBody;
214-
requestBody["query"] = MODEL_ZOO_QUERY;
215-
216-
// Add REQUIRED parameters
217-
requestBody["variables"]["input"]["platform"] = modelDescription.platform;
218-
requestBody["variables"]["input"]["slug"] = modelDescription.model;
219-
220-
// Add OPTIONAL parameters
221-
if(!modelDescription.optimizationLevel.empty()) {
222-
requestBody["variables"]["input"]["optimizationLevel"] = modelDescription.optimizationLevel;
223-
}
224-
if(!modelDescription.compressionLevel.empty()) {
225-
requestBody["variables"]["input"]["compressionLevel"] = modelDescription.compressionLevel;
226-
}
227-
if(!modelDescription.snpeVersion.empty()) {
228-
requestBody["variables"]["input"]["snpeVersion"] = modelDescription.snpeVersion;
211+
// Add request parameters
212+
cpr::Parameters params;
213+
214+
// Required parameters
215+
// clang-format off
216+
std::vector<std::pair<std::string, std::string>> requiredParams = {
217+
{"slug", modelDescription.model},
218+
{"platform", modelDescription.platform}
219+
};
220+
// clang-format on
221+
for(const auto& param : requiredParams) {
222+
params.Add({param.first, param.second});
229223
}
230-
if(!modelDescription.modelPrecisionType.empty()) {
231-
requestBody["variables"]["input"]["modelPrecisionType"] = modelDescription.modelPrecisionType;
224+
225+
// Optional parameters
226+
// clang-format off
227+
std::vector<std::pair<std::string, std::string>> optionalParams = {
228+
{"optimizationLevel", modelDescription.optimizationLevel},
229+
{"compressionLevel", modelDescription.compressionLevel},
230+
{"snpeVersion", modelDescription.snpeVersion},
231+
{"modelPrecisionType", modelDescription.modelPrecisionType}
232+
};
233+
// clang-format on
234+
for(const auto& param : optionalParams) {
235+
if(!param.second.empty()) {
236+
params.Add({param.first, param.second});
237+
}
232238
}
239+
233240
// Set the Authorization headers
234241
cpr::Header headers = {
235242
{"Content-Type", "application/json"},
236243
};
237244
if(!apiKey.empty()) {
238245
headers["Authorization"] = "Bearer " + apiKey;
239246
}
240-
// Send HTTP request to Hub
241-
cpr::Response response = cpr::Post(cpr::Url{MODEL_ZOO_URL}, headers, cpr::Body{requestBody.dump()});
247+
248+
// Send HTTP GET request to REST endpoint
249+
cpr::Response response = cpr::Get(cpr::Url{MODEL_ZOO_URL}, headers, params);
242250
if(checkIsErrorHub(response)) {
243251
removeModelCacheFolder();
244252
throw std::runtime_error(generateErrorMessageHub(response));
245253
}
246254

247-
// Extract download link from response
255+
// Extract download links from response
248256
nlohmann::json responseJson = nlohmann::json::parse(response.text);
249-
auto downloadLinks = responseJson["data"]["ml"]["modelDownloads"]["data"].get<std::vector<std::string>>();
257+
auto downloadLinks = responseJson["download_links"].get<std::vector<std::string>>();
250258

251259
// Download all files and store them in cache folder
252260
for(const auto& downloadLink : downloadLinks) {

src/utility/EventsManager.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include "Environment.hpp"
1212
#include "Logging.hpp"
13+
#include "cpr/cpr.h"
14+
#include "depthai/schemas/Event.pb.h"
1315
namespace dai {
1416

1517
namespace utility {
@@ -101,18 +103,23 @@ EventsManager::EventsManager(std::string url, bool uploadCachedOnStart, float pu
101103
queueSize(10),
102104
publishInterval(publishInterval),
103105
logResponse(false),
104-
verifySsl(false),
106+
verifySsl(true),
105107
connected(false),
106108
cacheDir("/internal/private"),
107109
uploadCachedOnStart(uploadCachedOnStart),
108-
cacheIfCannotSend(false) {
110+
cacheIfCannotSend(false),
111+
stopEventBuffer(false) {
109112
sourceAppId = utility::getEnv("AGENT_APP_ID");
110113
sourceAppIdentifier = utility::getEnv("AGENT_APP_IDENTIFIER");
111114
token = utility::getEnv("DEPTHAI_HUB_API_KEY");
115+
if(token.empty()) {
116+
throw std::runtime_error("Missing token, please set DEPTHAI_HUB_API_KEY environment variable or use setToken method");
117+
}
112118
eventBufferThread = std::make_unique<std::thread>([this]() {
113-
while(true) {
119+
while(!stopEventBuffer) {
114120
sendEventBuffer();
115-
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(this->publishInterval * 1000)));
121+
std::unique_lock<std::mutex> lock(eventBufferMutex);
122+
eventBufferCondition.wait_for(lock, std::chrono::seconds(static_cast<int>(this->publishInterval)));
116123
}
117124
});
118125
checkConnection();
@@ -122,7 +129,14 @@ EventsManager::EventsManager(std::string url, bool uploadCachedOnStart, float pu
122129
}
123130

124131
EventsManager::~EventsManager() {
125-
eventBufferThread->join();
132+
stopEventBuffer = true;
133+
{
134+
std::unique_lock<std::mutex> lock(eventBufferMutex);
135+
eventBufferCondition.notify_one();
136+
}
137+
if(eventBufferThread->joinable()) {
138+
eventBufferThread->join();
139+
}
126140
}
127141

128142
void EventsManager::sendEventBuffer() {
@@ -138,16 +152,26 @@ void EventsManager::sendEventBuffer() {
138152
}
139153
return;
140154
}
141-
// Create request
142-
cpr::Url url = static_cast<cpr::Url>(this->url + "/v1/events");
143155
for(auto& eventM : eventBuffer) {
144156
auto& event = eventM->event;
145157
batchEvent->add_events()->Swap(event.get());
146158
}
147159
}
148160
std::string serializedEvent;
149161
batchEvent->SerializeToString(&serializedEvent);
150-
cpr::Response r = cpr::Post(cpr::Url{url}, cpr::Body{serializedEvent}, cpr::Header{{"Authorization", "Bearer " + token}}, cpr::VerifySsl(verifySsl));
162+
cpr::Url reqUrl = static_cast<cpr::Url>(this->url + "/v1/events");
163+
cpr::Response r = cpr::Post(
164+
cpr::Url{reqUrl},
165+
cpr::Body{serializedEvent},
166+
cpr::Header{{"Authorization", "Bearer " + token}},
167+
cpr::VerifySsl(verifySsl),
168+
cpr::ProgressCallback(
169+
[&](cpr::cpr_off_t downloadTotal, cpr::cpr_off_t downloadNow, cpr::cpr_off_t uploadTotal, cpr::cpr_off_t uploadNow, intptr_t userdata) -> bool {
170+
if(stopEventBuffer) {
171+
return false;
172+
}
173+
return true;
174+
}));
151175
if(r.status_code != cpr::status::HTTP_OK) {
152176
logger::error("Failed to send event: {} {}", r.text, r.status_code);
153177
} else {
@@ -272,7 +296,19 @@ void EventsManager::sendFile(const std::shared_ptr<EventData>& file, const std::
272296
}};
273297
header["File-Size"] = std::to_string(std::filesystem::file_size(file->data));
274298
}
275-
cpr::Response r = cpr::Post(cpr::Url{url}, cpr::Multipart{fileM}, cpr::Header{header}, cpr::VerifySsl(verifySsl));
299+
cpr::Response r = cpr::Post(
300+
cpr::Url{url},
301+
cpr::Multipart{fileM},
302+
cpr::Header{header},
303+
cpr::VerifySsl(verifySsl),
304+
305+
cpr::ProgressCallback(
306+
[&](cpr::cpr_off_t downloadTotal, cpr::cpr_off_t downloadNow, cpr::cpr_off_t uploadTotal, cpr::cpr_off_t uploadNow, intptr_t userdata) -> bool {
307+
if(stopEventBuffer) {
308+
return false;
309+
}
310+
return true;
311+
}));
276312
if(r.status_code != cpr::status::HTTP_OK) {
277313
logger::error("Failed to upload file: {} error code {}", r.text, r.status_code);
278314
}

0 commit comments

Comments
 (0)