diff --git a/CMakeLists.txt b/CMakeLists.txt index 103c3b1..eff65b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,15 @@ cmake_minimum_required(VERSION 3.16) project(WaterLevelRewrite VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTORCC ON) -find_package(Qt6 REQUIRED COMPONENTS Quick) +find_package(Qt6 REQUIRED COMPONENTS Quick Multimedia) qt_standard_project_setup(REQUIRES 6.10) qt_add_executable(appWaterLevelRewrite main.cpp + media.qrc ) qt_add_qml_module(appWaterLevelRewrite @@ -22,11 +24,9 @@ qt_add_qml_module(appWaterLevelRewrite SOURCES configinterface.h configinterface.cpp QML_FILES ConnectButton.qml SOURCES requestworker.h requestworker.cpp + RESOURCES media.qrc ) -# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. -# If you are developing for iOS or macOS you should consider setting an -# explicit, fixed bundle identifier manually though. set_target_properties(appWaterLevelRewrite PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appWaterLevelRewrite MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} @@ -36,7 +36,7 @@ set_target_properties(appWaterLevelRewrite PROPERTIES ) target_link_libraries(appWaterLevelRewrite - PRIVATE Qt6::Quick + PRIVATE Qt6::Quick Qt6::Multimedia ) install(TARGETS appWaterLevelRewrite diff --git a/Main.qml b/Main.qml index 950a2b9..1b6c5fc 100644 --- a/Main.qml +++ b/Main.qml @@ -21,7 +21,8 @@ Window { property int distance_count_thres: 3 property string mode: "http" property string status: "Initializing" - + property string alarm_status_text: "" + property var root_config: ({}) Rectangle { anchors.fill: parent @@ -91,11 +92,13 @@ Window { max_thres_input: 0 } + Text { - id: status - text: root.status + id: alarm_status + text: root.alarm_status_text + visible: (root.alarm_status_text.length > 0 ) ? true : false anchors { - bottom: connect_button.top + bottom: status.top bottomMargin: 20 horizontalCenter: parent.horizontalCenter } @@ -104,32 +107,90 @@ Window { font.pointSize: root.font_normal_text_size } - ConnectButton { - id: connect_button + Text { + id: status + text: root.status + anchors { + bottom: button_base.top + bottomMargin: 20 + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + color: root.accent_color + font.pointSize: root.font_normal_text_size + } + + Rectangle { + id: button_base + color: "#00000000" + width: parent.width / 1.5 height: parent.height / 20 - width: parent.width / 4 - font_color: root.accent_color - font_enlarged_text_size: root.font_enlarged_text_size - font_normal_text_size: root.font_normal_text_size - color: root.background_color - accent_color: root.accent_color anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom bottomMargin: 50 } - onConnect: { - if(connect_button.mode === 0) - { - requester.start(); - root.status = "Waiting to Send."; + ConnectButton { + id: connect_button + width: parent.width / 2.1 + height: parent.height + font_color: root.accent_color + font_enlarged_text_size: root.font_enlarged_text_size + font_normal_text_size: root.font_normal_text_size + color: root.background_color + accent_color: root.accent_color + anchors { + left: parent.left + leftMargin: 5 + bottom: parent.bottom + bottomMargin: 5 } - else { - root.status = "Stopped."; - requester.stop(); + onConnect: { + if(connect_button.mode === 0) + { + requester.start(); + root.status = "Waiting to Send."; + } + else { + root.status = "Stopped."; + requester.stop(); + } } } + + ConnectButton { + id: start_alarm + width: parent.width / 2.1 + height: parent.height + font_color: root.accent_color + font_enlarged_text_size: root.font_enlarged_text_size + font_normal_text_size: root.font_normal_text_size + color: root.background_color + accent_color: root.accent_color + text: "Start Alarm" + text2: "Stop Alarm" + anchors { + left: connect_button.right + leftMargin: 10 + bottom: parent.bottom + bottomMargin: 5 + } + onConnect: { + if(start_alarm.mode === 0) + { + requester.startAlarm(); + root.alarm_status_text = "Started Alarm; Waiting for Trigger: " + root.root_config.alert + "%" + } + else { + requester.stopAlarm(); + root.alarm_status_text = ""; + } + } + } + } + + } RequestWorker { @@ -162,6 +223,10 @@ Window { function setConfig(config) { tank.setConfig(config); requester.setConfig(config); + root.root_config = config; } } + onClosing: { + requester.stopAlarm(); + } } diff --git a/echo.mp3 b/echo.mp3 new file mode 100644 index 0000000..4373d95 Binary files /dev/null and b/echo.mp3 differ diff --git a/media.qrc b/media.qrc new file mode 100644 index 0000000..2af454f --- /dev/null +++ b/media.qrc @@ -0,0 +1,5 @@ + + + echo.mp3 + + diff --git a/requestworker.cpp b/requestworker.cpp index 649d515..c02ea40 100644 --- a/requestworker.cpp +++ b/requestworker.cpp @@ -3,6 +3,7 @@ #include #include #include +#include RequestWorker::RequestWorker(QObject *parent) : QObject{parent} @@ -16,11 +17,13 @@ void RequestWorker::setConfig(QJsonObject config) this->interval = config["interval"].toInt(); this->max_height = config["max"].toInt(); this->min_height = config["min"].toInt(); + this->alarm_thres = config["alert"].toInt(); qDebug() << "In cpp config values are: "; qDebug() << "Url: " << url; qDebug() << "Interval: " << interval; qDebug() << "Max Height: " << max_height; qDebug() << "Min Height: " << min_height; + qDebug() << "Alert: " << alarm_thres; } void RequestWorker::start() @@ -51,6 +54,34 @@ void RequestWorker::stop() qDebug() << "Stopping" << timer->isActive(); } +void RequestWorker::playAlarm() +{ + if(player_started) + return; + if(player) { + player->deleteLater(); + player = nullptr; + } + if(audioOutput) { + audioOutput->deleteLater(); + audioOutput->deleteLater(); + } + qDebug() << "Loading player"; + player = new QMediaPlayer(this); + audioOutput = new QAudioOutput(this); + player->setAudioOutput(audioOutput); + if (QFile::exists(":/sounds/echo.mp3")) { + qDebug() << "Resource found successfully!"; + } else { + qDebug() << "Resource not found. Check CMakeLists.txt or .pro file!"; + } + player->setSource(QUrl("qrc:/sounds/echo.mp3")); + audioOutput->setVolume(0.5); + connect(this, &RequestWorker::playMedia, player, &QMediaPlayer::play); + player_started = true; + emit playMedia(); +} + void RequestWorker::makeRequest() { if(stop_timer) @@ -85,6 +116,13 @@ void RequestWorker::requestFinished(QNetworkReply *rep) float rate_of_fill = ( float )(prev_distance - water_level) /(float) time_in_microseconds; rate_of_fill = rate_of_fill * 1'000'000; int expected_to_fill = (water_level - min_height) / rate_of_fill; + int percentage_filled = (float (max_height - water_level) / float (max_height)) *100; + if(enable_alarm) { + qDebug() << "Alarm enabled"; + if(percentage_filled >= alarm_thres) { + playAlarm(); + } + } if(reply_number == 0) { rate_of_fill = 0; expected_to_fill = 0; @@ -93,6 +131,7 @@ void RequestWorker::requestFinished(QNetworkReply *rep) qDebug() << "Got water level: " << water_level; qDebug() << "Got rate of fill: " << rate_of_fill; qDebug() << "Got expected to fill: " << expected_to_fill; + qDebug() << "Percentage filled: " << percentage_filled; qDebug() << "Time difference: " << time_in_microseconds; prev_distance = water_level; emit networkReply(data_water_level, rate_of_fill, expected_to_fill); @@ -118,3 +157,23 @@ void RequestWorker::setStatus(const QString &newStatus) m_status = newStatus; emit statusChanged(); } + +void RequestWorker::startAlarm() +{ + enable_alarm = true; +} + +void RequestWorker::stopAlarm() +{ + enable_alarm = false; + player_started = false; + if(player) { + player->stop(); + player->deleteLater(); + player = nullptr; + } + if(audioOutput) { + audioOutput->deleteLater(); + audioOutput = nullptr; + } +} diff --git a/requestworker.h b/requestworker.h index 37d0888..f78e3a6 100644 --- a/requestworker.h +++ b/requestworker.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include @@ -24,10 +26,14 @@ class RequestWorker : public QObject int min_height = 0; bool stop_timer = false; int reply_number = 0; + int alarm_thres = 0; + bool enable_alarm = false; + bool player_started = false; + QMediaPlayer *player = nullptr; + QAudioOutput *audioOutput = nullptr; std::chrono::time_point prev_time; public: explicit RequestWorker(QObject *parent = nullptr); - QString status() const; void setStatus(const QString &newStatus); @@ -35,12 +41,15 @@ signals: void requestFailed(); void networkReply(int distance, float rate_of_fill, int expected_to_fill); void statusChanged(); - + void playMedia(); public slots: + void startAlarm(); + void stopAlarm(); void setConfig(QJsonObject config); void start(); void stop(); private slots: + void playAlarm(); void makeRequest(); void requestFinished(QNetworkReply *rep); private: