From 331390ea204d6379abcbc53b28adbd2ed4dd69a3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Sep 2024 12:27:26 -0400 Subject: [PATCH] Move Poller_Healthy and Trigger state into Amcrest_API and ONVIF modules. Add lastTopic and lastValue to onvif. Add values to event notes. Reverse logic for event ending to look for false, as the value could be other things like isMotion or IsPeople. --- src/zm_monitor.cpp | 13 +++++-------- src/zm_monitor.h | 23 +++++++++++++++++------ src/zm_monitor_amcrest.cpp | 18 ++++++++++-------- src/zm_monitor_onvif.cpp | 29 ++++++++++++++++------------- 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 05ea6d6df..77a43c9fd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -316,8 +316,6 @@ Monitor::Monitor() : //linked_monitors_string n_linked_monitors(0), linked_monitors(nullptr), - Poll_Trigger_State(false), - Event_Poller_Healthy(false), Event_Poller_Closes_Event(false), RTSP2Web_Manager(nullptr), Janus_Manager(nullptr), @@ -1168,10 +1166,8 @@ bool Monitor::connect() { //ONVIF and Amcrest Setup //For now, only support one event type per camera, so share some state. - Poll_Trigger_State = false; if (onvif_event_listener) { // Debug(1, "Starting ONVIF"); - Event_Poller_Healthy = false; if (onvif_options.find("closes_event") != std::string::npos) { //Option to indicate that ONVIF will send a close event message Event_Poller_Closes_Event = true; } @@ -1871,7 +1867,7 @@ bool Monitor::Poll() { std::chrono::system_clock::time_point loop_start_time = std::chrono::system_clock::now(); if (use_Amcrest_API) { - if (Event_Poller_Healthy) { + if (Amcrest_Manager->isHealthy()) { Amcrest_Manager->WaitForMessage(); } else { delete Amcrest_Manager; @@ -1950,17 +1946,18 @@ bool Monitor::Analyse() { Event::StringSetMap noteSetMap; #ifdef WITH_GSOAP - if (onvif_event_listener && Event_Poller_Healthy) { - if ((onvif and onvif->isAlarmed()) or Poll_Trigger_State) { + if (onvif_event_listener) { + if ((onvif and onvif->isAlarmed()) or (Amcrest_Manager and Amcrest_Manager->isAlarmed())) { score += 9; Debug(4, "Triggered on ONVIF"); Event::StringSet noteSet; noteSet.insert("ONVIF"); + noteSet.insert(onvif->lastTopic() + '/' + onvif->lastValue()); noteSetMap[MOTION_CAUSE] = noteSet; cause += "ONVIF"; // If the camera isn't going to send an event close, we need to close it here, but only after it has actually triggered an alarm. if (!Event_Poller_Closes_Event && state == ALARM) - Poll_Trigger_State = false; + onvif->setAlarmed(false); } // end ONVIF_Trigger } // end if (onvif_event_listener && Event_Poller_Healthy) #endif diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 083eba695..7ea14b0ac 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -326,6 +326,8 @@ class Monitor : public std::enable_shared_from_this { Monitor *parent; bool alarmed; bool healthy; + std::string last_topic; + std::string last_value; #ifdef WITH_GSOAP struct soap *soap = nullptr; _tev__CreatePullPointSubscription request; @@ -343,12 +345,17 @@ class Monitor : public std::enable_shared_from_this { void start(); void WaitForMessage(); bool isAlarmed() const { return alarmed; }; + void setAlarmed(bool p_alarmed) { alarmed = p_alarmed; }; bool isHealthy() const { return healthy; }; + const std::string &lastTopic() const { return last_topic; }; + const std::string &lastValue() const { return last_value; }; }; class AmcrestAPI { protected: Monitor *parent; + bool alarmed; + bool healthy; std::string amcrest_response; CURLM *curl_multi = nullptr; CURL *Amcrest_handle = nullptr; @@ -359,8 +366,9 @@ class Monitor : public std::enable_shared_from_this { ~AmcrestAPI(); int API_Connect(); void WaitForMessage(); - bool Amcrest_Alarmed; - int start_Amcrest(); + int start(); + bool isAlarmed() const { return alarmed; }; + bool isHealthy() const { return healthy; }; }; class RTSP2WebManager { @@ -631,8 +639,6 @@ class Monitor : public std::enable_shared_from_this { std::string diag_path_delta; //ONVIF - bool Poll_Trigger_State; - bool Event_Poller_Healthy; bool Event_Poller_Closes_Event; RTSP2WebManager *RTSP2Web_Manager; @@ -718,8 +724,13 @@ class Monitor : public std::enable_shared_from_this { return onvif_event_listener; } int check_janus(); //returns 1 for healthy, 0 for success but missing stream, negative for error. - bool EventPollerHealthy() { - return Event_Poller_Healthy; + bool EventPollerHealthy() const { + if (onvif) { + return onvif->isHealthy(); + } else if (Amcrest_Manager) { + return Amcrest_Manager->isHealthy(); + } + return false; } inline const char *EventPrefix() const { return event_prefix.c_str(); } inline bool Ready() const { diff --git a/src/zm_monitor_amcrest.cpp b/src/zm_monitor_amcrest.cpp index 5d2526503..c46e7bdac 100644 --- a/src/zm_monitor_amcrest.cpp +++ b/src/zm_monitor_amcrest.cpp @@ -21,9 +21,11 @@ Monitor::AmcrestAPI::AmcrestAPI(Monitor *parent_) : parent(parent_), - Amcrest_Alarmed(false) { + alarmed(false), + healthy(false) +{ curl_multi = curl_multi_init(); - start_Amcrest(); + start(); } Monitor::AmcrestAPI::~AmcrestAPI() { @@ -34,7 +36,7 @@ Monitor::AmcrestAPI::~AmcrestAPI() { if (curl_multi != nullptr) curl_multi_cleanup(curl_multi); } -int Monitor::AmcrestAPI::start_Amcrest() { +int Monitor::AmcrestAPI::start() { // init the transfer and start it in multi-handle int running_handles; long response_code; @@ -76,7 +78,7 @@ int Monitor::AmcrestAPI::start_Amcrest() { } if ((curl_error == CURLM_OK) && (running_handles > 0)) { - parent->Event_Poller_Healthy = true; + healthy = true; Debug(1, "AMCREST Healthy"); } else { Warning("AMCREST Response: %s", amcrest_response.c_str()); @@ -94,7 +96,7 @@ void Monitor::AmcrestAPI::WaitForMessage() { int transfers; curl_multi_perform(curl_multi, &open_handles); if (open_handles == 0) { - start_Amcrest(); // http transfer ended, need to restart. + start(); // http transfer ended, need to restart. } else { // wait for max 5 seconds for event. curl_multi_wait(curl_multi, nullptr, 0, 5000, &transfers); @@ -104,13 +106,13 @@ void Monitor::AmcrestAPI::WaitForMessage() { if (amcrest_response.find("action=Start") != std::string::npos) { // Event Start Debug(1, "AMCREST Triggered on ONVIF"); - if (!parent->Poll_Trigger_State) { + if (!alarmed) { Debug(1, "AMCREST Triggered Event"); - parent->Poll_Trigger_State = true; + alarmed = true; } } else if (amcrest_response.find("action=Stop") != std::string::npos) { Debug(1, "AMCREST Triggered off ONVIF"); - parent->Poll_Trigger_State = false; + alarmed = false; if (!parent->Event_Poller_Closes_Event) { // If we get a close event, then we know to expect them. parent->Event_Poller_Closes_Event = true; Debug(1, "AMCREST Setting ClosesEvent"); diff --git a/src/zm_monitor_onvif.cpp b/src/zm_monitor_onvif.cpp index d7f18d134..f55d3f550 100644 --- a/src/zm_monitor_onvif.cpp +++ b/src/zm_monitor_onvif.cpp @@ -168,7 +168,7 @@ void Monitor::ONVIF::WaitForMessage() { for (auto msg : tev__PullMessagesResponse.wsnt__NotificationMessage) { if ((msg->Topic != nullptr) && (msg->Topic->__any.text != nullptr) && - std::strstr(msg->Topic->__any.text, parent->onvif_alarm_txt.c_str()) && + (parent->onvif_alarm_txt.empty() || std::strstr(msg->Topic->__any.text, parent->onvif_alarm_txt.c_str())) && (msg->Message.__any.elts != nullptr) && (msg->Message.__any.elts->next != nullptr) && (msg->Message.__any.elts->next->elts != nullptr) && @@ -176,26 +176,29 @@ void Monitor::ONVIF::WaitForMessage() { (msg->Message.__any.elts->next->elts->atts->next != nullptr) && (msg->Message.__any.elts->next->elts->atts->next->text != nullptr) ) { - Info("Got Motion Alarm!"); - if (strcmp(msg->Message.__any.elts->next->elts->atts->next->text, "true") == 0) { - // Event Start - Info("Triggered on ONVIF"); - if (!alarmed) { - Info("Triggered Event"); - alarmed = true; - // Why sleep? - std::this_thread::sleep_for(std::chrono::seconds(1)); //thread sleep - } - } else { + Info("ONVIF Got Motion Alarm! %s %s", msg->Topic->__any.text, msg->Message.__any.elts->next->elts->atts->next->text); + // Apparently simple motion events, the value is boolean, but for people detection can be things like isMotion, isPeople + if (strcmp(msg->Message.__any.elts->next->elts->atts->next->text, "false") == 0) { Info("Triggered off ONVIF"); alarmed = false; if (!parent->Event_Poller_Closes_Event) { //If we get a close event, then we know to expect them. parent->Event_Poller_Closes_Event = true; Info("Setting ClosesEvent"); } + } else { + // Event Start + Info("Triggered on ONVIF"); + if (!alarmed) { + Info("Triggered Event"); + alarmed = true; + last_topic = msg->Topic->__any.text; + last_value = msg->Message.__any.elts->next->elts->atts->next->text; + // Why sleep? + std::this_thread::sleep_for(std::chrono::seconds(1)); //thread sleep + } } } else { - Debug(1, "Got a message that we couldn't parse"); + Debug(1, "ONVIF Got a message that we couldn't parse"); if ((msg->Topic != nullptr) && (msg->Topic->__any.text != nullptr)) { Debug(1, "text was %s", msg->Topic->__any.text); }