From 40fc8ade20215e619b09e4c645cb8bb248bf4184 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Dec 2023 07:44:27 -0600 Subject: [PATCH] Handle received alerts and test against location for playing alert audio --- .../source/scwx/qt/manager/alert_manager.cpp | 104 +++++++++++++++++- .../scwx/qt/settings/audio_settings.cpp | 7 +- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/alert_manager.cpp b/scwx-qt/source/scwx/qt/manager/alert_manager.cpp index c7c9f7e1..93d4395f 100644 --- a/scwx-qt/source/scwx/qt/manager/alert_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/alert_manager.cpp @@ -1,10 +1,16 @@ #include +#include #include +#include #include #include +#include #include +#include +#include #include +#include namespace scwx { @@ -28,23 +34,119 @@ public: audioSettings.alert_location_method().RegisterValueChangedCallback( [this](const std::string& value) { UpdateLocationTracking(value); }); + + QObject::connect( + textEventManager_.get(), + &manager::TextEventManager::AlertUpdated, + self_, + [this](const types::TextEventKey& key, size_t messageIndex) + { + boost::asio::post(threadPool_, + [=, this]() { HandleAlert(key, messageIndex); }); + }); } - ~Impl() {} + ~Impl() { threadPool_.join(); } + common::Coordinate CurrentCoordinate() const; + void HandleAlert(const types::TextEventKey& key, size_t messageIndex) const; void UpdateLocationTracking(const std::string& value) const; + boost::asio::thread_pool threadPool_ {1u}; + AlertManager* self_; boost::uuids::uuid uuid_ {boost::uuids::random_generator()()}; + std::shared_ptr mediaManager_ {MediaManager::Instance()}; std::shared_ptr positionManager_ { PositionManager::Instance()}; + std::shared_ptr textEventManager_ { + TextEventManager::Instance()}; }; AlertManager::AlertManager() : p(std::make_unique(this)) {} AlertManager::~AlertManager() = default; +common::Coordinate AlertManager::Impl::CurrentCoordinate() const +{ + settings::AudioSettings& audioSettings = settings::AudioSettings::Instance(); + common::Coordinate coordinate {}; + + types::LocationMethod locationMethod = types::GetLocationMethod( + audioSettings.alert_location_method().GetValue()); + + if (locationMethod == types::LocationMethod::Fixed) + { + coordinate.latitude_ = audioSettings.alert_latitude().GetValue(); + coordinate.longitude_ = audioSettings.alert_longitude().GetValue(); + } + else if (locationMethod == types::LocationMethod::Track) + { + QGeoPositionInfo position = positionManager_->position(); + if (position.isValid()) + { + QGeoCoordinate trackedCoordinate = position.coordinate(); + coordinate.latitude_ = trackedCoordinate.latitude(); + coordinate.longitude_ = trackedCoordinate.longitude(); + } + } + + return coordinate; +} + +void AlertManager::Impl::HandleAlert(const types::TextEventKey& key, + size_t messageIndex) const +{ + // Skip alert if there are more messages to be processed + if (messageIndex + 1 < textEventManager_->message_count(key)) + { + return; + } + + settings::AudioSettings& audioSettings = settings::AudioSettings::Instance(); + common::Coordinate currentCoordinate = CurrentCoordinate(); + + auto message = textEventManager_->message_list(key).at(messageIndex); + + for (auto& segment : message->segments()) + { + if (!segment->codedLocation_.has_value()) + { + continue; + } + + auto& vtec = segment->header_->vtecString_.front(); + auto action = vtec.pVtec_.action(); + awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); + auto eventEnd = vtec.pVtec_.event_end(); + bool alertActive = (action != awips::PVtec::Action::Canceled); + + // If the event has ended or is inactive, or if the alert is not enabled, + // skip it + if (eventEnd < std::chrono::system_clock::now() || !alertActive || + !audioSettings.alert_enabled(phenomenon).GetValue()) + { + continue; + } + + // Determine if the alert is active at the current coordinte + auto alertCoordinates = segment->codedLocation_->coordinates(); + + if (util::GeographicLib::AreaContainsPoint(alertCoordinates, + currentCoordinate)) + { + logger_->info("Alert active at current location: {} {}.{} {}", + vtec.pVtec_.office_id(), + awips::GetPhenomenonCode(vtec.pVtec_.phenomenon()), + awips::PVtec::GetActionCode(vtec.pVtec_.action()), + vtec.pVtec_.event_tracking_number()); + + mediaManager_->Play(types::AudioFile::EasAttentionSignal); + } + } +} + void AlertManager::Impl::UpdateLocationTracking( const std::string& locationMethodName) const { diff --git a/scwx-qt/source/scwx/qt/settings/audio_settings.cpp b/scwx-qt/source/scwx/qt/settings/audio_settings.cpp index 869973ae..2d2844cd 100644 --- a/scwx-qt/source/scwx/qt/settings/audio_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/audio_settings.cpp @@ -17,8 +17,7 @@ namespace settings static const std::string logPrefix_ = "scwx::qt::settings::audio_settings"; static const bool kDefaultAlertEnabled_ {false}; -static const awips::Phenomenon kDefaultPhenomenon_ { - awips::Phenomenon::FlashFlood}; +static const awips::Phenomenon kDefaultPhenomenon_ {awips::Phenomenon::Unknown}; class AudioSettings::Impl { @@ -58,6 +57,10 @@ public: variables_.push_back(&variable); } + + // Create a default disabled alert, not stored in the settings file + alertEnabled_.emplace(kDefaultPhenomenon_, + SettingsVariable {"alert_disabled"}); } ~Impl() {}