From 026ea972841109f1e324073b536de5971e9b7cf2 Mon Sep 17 00:00:00 2001 From: unrealdragon Date: Tue, 4 Aug 2026 21:31:40 +0530 Subject: [PATCH] Http Version - Initial Commit --- .gitignore | 2 + CMakeLists.txt | 46 ++++++++ ConnectButton.qml | 55 ++++++++++ Main.qml | 156 +++++++++++++++++++++++++++ SettingsBarIcon.qml | 46 ++++++++ SettingsPopup.qml | 251 ++++++++++++++++++++++++++++++++++++++++++++ WaterTank.qml | 162 ++++++++++++++++++++++++++++ configinterface.cpp | 53 ++++++++++ configinterface.h | 28 +++++ main.cpp | 18 ++++ requestworker.cpp | 112 ++++++++++++++++++++ requestworker.h | 49 +++++++++ 12 files changed, 978 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 ConnectButton.qml create mode 100644 Main.qml create mode 100644 SettingsBarIcon.qml create mode 100644 SettingsPopup.qml create mode 100644 WaterTank.qml create mode 100644 configinterface.cpp create mode 100644 configinterface.h create mode 100644 main.cpp create mode 100644 requestworker.cpp create mode 100644 requestworker.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9e89eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/* +.qtcreator/* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..103c3b1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.16) + +project(WaterLevelRewrite VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Quick) + +qt_standard_project_setup(REQUIRES 6.10) + +qt_add_executable(appWaterLevelRewrite + main.cpp +) + +qt_add_qml_module(appWaterLevelRewrite + URI WaterLevelRewrite + QML_FILES + Main.qml + QML_FILES WaterTank.qml + QML_FILES SettingsBarIcon.qml + QML_FILES SettingsPopup.qml + SOURCES configinterface.h configinterface.cpp + QML_FILES ConnectButton.qml + SOURCES requestworker.h requestworker.cpp +) + +# 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} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +target_link_libraries(appWaterLevelRewrite + PRIVATE Qt6::Quick +) + +install(TARGETS appWaterLevelRewrite + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/ConnectButton.qml b/ConnectButton.qml new file mode 100644 index 0000000..9225e44 --- /dev/null +++ b/ConnectButton.qml @@ -0,0 +1,55 @@ +import QtQuick +import QtQuick.Effects +import QtQuick.Controls +import QtQuick.Controls.Material + +Rectangle { + id: root + property color accent_color: "#00000000" + property color font_color: "#00000000" + property int font_enlarged_text_size: 20 + property int font_normal_text_size: 16 + property string text: "Connect" + signal connect; + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + } + + Text { + anchors.centerIn: parent + font.pointSize: root.font_enlarged_text_size + color: root.font_color + text: root.text + horizontalAlignment: Text.AlignHCenter + } + + radius: 5 + border { + color: root.accent_color + width: 0.5 + } + MouseArea { + id: settings_button_area + anchors.fill: parent + hoverEnabled: true + property color settings_rect_pressed_prev: "#00000000" + property color settings_rect_entered_prev: "#00000000" + onEntered: { + settings_rect_entered_prev = root.color + root.color = "#5A1F1F1F" + } + onExited: { + root.color = settings_rect_entered_prev + } + onPressed: { + settings_rect_pressed_prev = root.color + root.color = "#5A1F4F1F" + root.connect(); + } + onReleased: { + root.color = settings_rect_pressed_prev + } + } + +} diff --git a/Main.qml b/Main.qml new file mode 100644 index 0000000..db445e4 --- /dev/null +++ b/Main.qml @@ -0,0 +1,156 @@ +import QtQuick +import WaterLevelRewrite +import QtQuick.Effects +import QtQuick.Controls +import QtQuick.Controls.Material + +Window { + width: 640 + height: 1080 + visible: true + title: qsTr("Water Level Rewrite") + id: root + property color accent_color: "#F05FAF5F" + property color dark_accent_color: "#FF5F7F5F" + property color danger_color: "#F0AF2F1F" + property color water_color: "#F00F7FAF" + property color background_color: "#1F1F1F" + Material.accent: root.accent_color + property int font_enlarged_text_size: 20 + property int font_normal_text_size: 16 + property int distance_count_thres: 3 + property string mode: "http" + property string status: "Initializing" + + + Rectangle { + anchors.fill: parent + color: root.background_color + + Rectangle { + id: top_bar + height: Math.min(root.height / 12, 100) + width: root.width + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + topMargin: 25 + } + color: "#0A0F0F0F" + SettingsBarIcon { + height: top_bar.height - 20 + width: top_bar.width / 12 + anchors { + top: parent.top + left: parent.left + bottomMargin: 5 + topMargin: 5 + leftMargin: 5 + } + color: "#0A0F0F0F" + radius: 100 + accent_color: root.accent_color + onOpen: { + settings_popup.open() + } + } + } + + SettingsPopup { + id: settings_popup + accent_color: root.accent_color + font_enlarged_text_size: 20 + function setConfig(new_config: var) { + settings_popup.config.max = new_config.max + settings_popup.config.min = new_config.min + settings_popup.config.alert = new_config.alert + settings_popup.config.url = new_config.url + } + onSaveConfig: (config) => { + console.log("Saving config: ", config) + config_interface.saveConfig(config); + } + } + + WaterTank { + id: tank + anchors { + top: top_bar.bottom + horizontalCenter: parent.horizontalCenter + topMargin: 0 + } + height: (parent.height - top_bar.height) / 1.2 + width: parent.width / 1.2 + base_color: root.background_color + distance: 0 + tank_lid_color: "#F0121212" + tank_base_color: "#0FFFFFFF" + water_level_color: "#F00F7FAF" + tank_base_border_color: "#F0121212" + min_thres_input: 0 + max_thres_input: 0 + } + + Text { + id: status + text: root.status + anchors { + bottom: connect_button.top + bottomMargin: 20 + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + color: root.accent_color + font.pointSize: root.font_normal_text_size + } + + ConnectButton { + id: connect_button + 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: { + requester.start(); + root.status = "Waiting to Send."; + } + } + } + + RequestWorker { + id: requester + onStatusChanged: () => { + root.status = requester.status; + } + onNetworkReply: (water_level, fill_rate, expected) => { + tank.setDistance(water_level); + tank.rate_of_fill = fill_rate; + tank.expected_to_fill = expected; + } + } + + ConfigInterface { + id: config_interface + fileName: "config.json" + onConfig: (config) => { + settings_popup.config = config + console.log("Loading initial config"); + setConfig(config); + if(root.status === "Initializing") { + root.status = "Waiting to connect."; + } + } + function setConfig(config) { + tank.setConfig(config); + requester.setConfig(config); + } + } +} diff --git a/SettingsBarIcon.qml b/SettingsBarIcon.qml new file mode 100644 index 0000000..d360331 --- /dev/null +++ b/SettingsBarIcon.qml @@ -0,0 +1,46 @@ +import QtQuick +import QtQuick.Effects +import QtQuick.Controls +import QtQuick.Controls.Material + +Rectangle { + id: settings_rect + signal open; + property color accent_color: "#00000000" + property int font_enlarged_text_size: 20 + Behavior on color { + ColorAnimation { + duration: 200 + } + } + Text { + id: settings_text + text: "⚙" + anchors.centerIn: parent + color: settings_rect.accent_color + font.pointSize: settings_rect.font_enlarged_text_size + } + + MouseArea { + id: settings_button_area + anchors.fill: parent + hoverEnabled: true + property color settings_rect_pressed_prev: "#00000000" + property color settings_rect_entered_prev: "#00000000" + onEntered: { + settings_rect_entered_prev = settings_rect.color + settings_rect.color = "#5A1F1F1F" + } + onExited: { + settings_rect.color = settings_rect_entered_prev + } + onPressed: { + settings_rect_pressed_prev = settings_rect.color + settings_rect.color = "#5A1F4F1F" + settings_rect.open(); + } + onReleased: { + settings_rect.color = settings_rect_pressed_prev + } + } +} diff --git a/SettingsPopup.qml b/SettingsPopup.qml new file mode 100644 index 0000000..051c306 --- /dev/null +++ b/SettingsPopup.qml @@ -0,0 +1,251 @@ +import QtQuick +import QtQuick.Effects +import QtQuick.Controls +import QtQuick.Controls.Material + +Popup { + id: settings_popup + signal saveConfig(config: var) + property color accent_color: "#00000000" + property int font_enlarged_text_size: 20 + property int font_normal_text_size: 16 + property var config: { + "max": 0, + "min": 0, + "alert": 0, + "interval": 0, + "url": "none" + } + + background: Rectangle { + color: "#F0121212" + radius: 5 + border.color: settings_popup.accent_color + border.width: 1 + } + height: Math.max(parent.height / 1.2, contentHeight) + width: parent.width / 1.1 + anchors.centerIn: Overlay.overlay + Rectangle { + id: settings_base + anchors.fill: parent + color: "#F0121212" + + Text { + id: settings_label + text: "Settings" + width: parent.width + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + color: settings_popup.accent_color + font.pointSize: settings_popup.font_enlarged_text_size + } + + + Text { + id: max_thres_label + text: "Max Threshold: " + anchors { + topMargin: 20 + top: settings_label.bottom + left: parent.left + verticalCenter: max_thres_input.verticalCenter + } + height: max_thres_input.height + verticalAlignment: Text.AlignVCenter + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + TextField { + id: max_thres_input + text: config.max + anchors { + right: parent.right + rightMargin: 5 + top: settings_label.bottom + topMargin: 20 + } + width: parent.width / 2 + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + + Text { + id: min_thres_label + text: "Min Threshold: " + anchors { + topMargin: 20 + top: max_thres_label.bottom + left: parent.left + verticalCenter: min_thres_input.verticalCenter + } + height: min_thres_input.height + verticalAlignment: Text.AlignVCenter + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + TextField { + id: min_thres_input + text: config.min + anchors { + right: parent.right + rightMargin: 5 + top: max_thres_label.bottom + topMargin: 20 + } + width: parent.width / 2 + color: root.accent_color + font.pointSize: root.font_normal_text_size + } + + + Text { + id: alert_thres_label + text: "Alert Percentage: " + anchors { + topMargin: 20 + top: min_thres_label.bottom + left: parent.left + verticalCenter: alert_thres_input.verticalCenter + } + height: alert_thres_input.height + verticalAlignment: Text.AlignVCenter + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + TextField { + id: alert_thres_input + text: config.alert + anchors { + right: parent.right + rightMargin: 5 + top: min_thres_label.bottom + topMargin: 20 + } + width: parent.width / 2 + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + Text { + id: interval_label + text: "Update Interval: " + anchors { + topMargin: 20 + top: alert_thres_label.bottom + left: parent.left + verticalCenter: interval_input.verticalCenter + } + height: interval_input.height + verticalAlignment: Text.AlignVCenter + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + + TextField { + id: interval_input + text: config.interval + anchors { + right: parent.right + rightMargin: 5 + top: alert_thres_input.bottom + topMargin: 20 + } + width: parent.width / 2 + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + Text { + id: http_url_label + text: "Url: " + anchors { + topMargin: 20 + top: interval_label.bottom + left: parent.left + verticalCenter: http_url_input.verticalCenter + } + height: http_url_input.height + verticalAlignment: Text.AlignVCenter + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + } + + TextField { + id: http_url_input + text: config.url + anchors { + right: parent.right + rightMargin: 20 + leftMargin: 20 + top: interval_input.bottom + topMargin: 20 + } + width: Math.max(parent.width / 2, parent.width - http_url_label.width - anchors.leftMargin) + color: settings_popup.accent_color + font.pointSize: settings_popup.font_normal_text_size + cursorPosition: 0 + } + + Rectangle { + id: save_config + anchors { + topMargin: 10 + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + color: "#F0121212" + width: parent.width / 1.3 + height: 60 + border { + width: 1 + color: settings_popup.accent_color + } + radius: 3 + + Text { + anchors.centerIn: parent + text: "Save" + color: settings_popup.accent_color + font.pointSize: settings_popup.font_enlarged_text_size + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + property color settings_rect_pressed_prev: "#00000000" + property color settings_rect_entered_prev: "#00000000" + onEntered: { + settings_rect_entered_prev = save_config.color + save_config.color = "#5A1F1F1F" + } + onExited: { + save_config.color = settings_rect_entered_prev + } + onPressed: { + settings_rect_pressed_prev = save_config.color + save_config.color = "#5A1F4F1F" + let max = parseFloat(max_thres_input.text); + let min = parseFloat(min_thres_input.text); + let alert = parseFloat(alert_thres_input.text); + let url = http_url_input.text; + let interval = parseInt(interval_input.text); + var new_config = {"max": max, "min": min, "alert": alert, "url": url, "interval": interval} + settings_popup.saveConfig(new_config) + settings_popup.close(); + } + onReleased: { + save_config.color = settings_rect_pressed_prev + } + } + + } + } +} \ No newline at end of file diff --git a/WaterTank.qml b/WaterTank.qml new file mode 100644 index 0000000..5c1b5af --- /dev/null +++ b/WaterTank.qml @@ -0,0 +1,162 @@ +import QtQuick +import QtQuick.Effects +import QtQuick.Controls +import QtQuick.Controls.Material + +Item { + id: root + property color base_color: "#000F0F0F" + property color tank_lid_color: "#F0121212" + property color tank_base_color: "#00FFFFFF" + property color water_level_color: "#F00F7FAF" + property color tank_base_border_color: "#F0121212" + property color text_color: "#F05FAF5F" + property double height_max: tank_base.height - 10 + property double current_level: 0 + property double percentage_filled: 0 + property double distance: 0 + property double min_thres_input: 0 + property double max_thres_input: 0 + property double rate_of_fill: 0 + property double expected_to_fill: 0 + + Rectangle { + id: base + color: root.base_color + anchors.fill: parent + Rectangle { + id: tank_lid + color: root.tank_lid_color + anchors { + bottom: tank_base.top + horizontalCenter: tank_base.horizontalCenter + bottomMargin: -5 + } + radius: 10 + width: parent.width / 4 + height: parent.height / 15 + } + + Rectangle { + id: tank_base + color: root.tank_base_color + anchors.centerIn: parent + width: parent.width / 2 + height: parent.height / 2 + border.color: root.tank_base_border_color + border.width: 5 + radius: 4 + } + + Rectangle { + id: water_level + color: root.water_level_color + height: root.current_level + width: tank_base.width - 10 + anchors { + bottom: tank_base.bottom + horizontalCenter: tank_base.horizontalCenter + bottomMargin: 5 + } + Behavior on color { + ColorAnimation { + duration: 200 + } + } + Behavior on height { + NumberAnimation { + duration: 200 + } + } + } + + Text { + id: water_level_reading + text: "Current Reading: " + root.distance + " cm" + font.pointSize: 16 + color: root.text_color + anchors { + margins: 5 + top: tank_base.bottom + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + } + + Text { + id: water_level_percentage + text: "Percentage: " + root.percentage_filled + " %" + font.pointSize: 16 + color: root.text_color + anchors { + margins: 5 + top: water_level_reading.bottom + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + } + + Text { + id: fill_status + text: "Filling status: " + (( root.rate_of_fill > 0)? "Filling" : "Discharging") + font.pointSize: 16 + color: root.text_color + anchors { + margins: 5 + top: water_level_percentage.bottom + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + } + Text { + id: rate_of_fill_label + text: "Rate of fill: " + root.rate_of_fill + " cm/s" + font.pointSize: 16 + color: root.text_color + anchors { + margins: 5 + top: fill_status.bottom + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + } + Text { + id: expected_to_fill_label + text: "Expected to fill in: " + root.expected_to_fill + " s" + font.pointSize: 16 + color: root.text_color + visible: (root.rate_of_fill > 1) ? true : false + anchors { + margins: 5 + top: rate_of_fill_label.bottom + horizontalCenter: parent.horizontalCenter + } + horizontalAlignment: Text.AlignHCenter + } + } + function setConfig(config: var) { + min_thres_input = config.min; + max_thres_input = config.max; + } + + function setDistance(distance) { + root.distance = distance; + console.log("Distance changed to: ", distance); + let current_min_reading = Math.max(0, min_thres_input); + let effective_max_reading = Math.max(0, max_thres_input) - current_min_reading; + let current_reading = Math.max(0, root.distance - current_min_reading); + console.log("Current reading is: " + current_reading) + console.log("Current min reading is: " + current_min_reading) + console.log("Effective max reading is: " + effective_max_reading) + + let height_max_possible = root.height_max; + let percentage_filled = Math.max(0, ((effective_max_reading - current_reading) / effective_max_reading * 100)) + let normalized_height = percentage_filled * height_max_possible / 100; + console.log("Current reading is: " + current_reading) + console.log("Normalized height is: " + normalized_height) + console.log("Percentage filled is: " + percentage_filled) + root.current_level = normalized_height; + root.percentage_filled = percentage_filled; + } +} + diff --git a/configinterface.cpp b/configinterface.cpp new file mode 100644 index 0000000..258560f --- /dev/null +++ b/configinterface.cpp @@ -0,0 +1,53 @@ +#include "configinterface.h" + +#include +#include + +ConfigInterface::ConfigInterface(QObject *parent) + : QObject{parent} +{ +} + +QString ConfigInterface::fileName() const +{ + return m_fileName; +} + +void ConfigInterface::setFileName(const QString &newFileName) +{ + if (m_fileName == newFileName) + return; + m_fileName = newFileName; + std::fstream input(newFileName.toStdString(), std::fstream::in); + if(!input.is_open()) { + return; + } + std::string data; + std::string temp; + while(std::getline(input, temp)) { + data += temp; + } + input.flush(); + input.close(); + QByteArray arr_data(data); + QJsonDocument doc = QJsonDocument::fromJson(arr_data); + // The following works even the qml part is not initailzed/connected + // do not change back to just emit config() + QMetaObject::invokeMethod(this, &ConfigInterface::config, Qt::QueuedConnection, doc.object()); + emit fileNameChanged(); +} + +void ConfigInterface::saveConfig(QJsonObject config) +{ + QJsonDocument doc; + doc.setObject(config); + std::string data = doc.toJson().toStdString(); + std::fstream output(m_fileName.toStdString(), std::fstream::out); + if(!output.is_open()) { + return; + } + output << data; + output.flush(); + output.close(); + QMetaObject::invokeMethod(this, &ConfigInterface::config, Qt::QueuedConnection, doc.object()); +} diff --git a/configinterface.h b/configinterface.h new file mode 100644 index 0000000..606b496 --- /dev/null +++ b/configinterface.h @@ -0,0 +1,28 @@ +#ifndef CONFIGINTERFACE_H +#define CONFIGINTERFACE_H + +#include +#include +#include +#include +#include + +class ConfigInterface : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QString fileName READ fileName WRITE setFileName NOTIFY fileNameChanged FINAL) +public: + explicit ConfigInterface(QObject *parent = nullptr); + QString fileName() const; + void setFileName(const QString &newFileName); +signals: + void config(QJsonObject config); + void fileNameChanged(); +public slots: + void saveConfig(QJsonObject config); +private: + QString m_fileName; +}; + +#endif // CONFIGINTERFACE_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..c438cd2 --- /dev/null +++ b/main.cpp @@ -0,0 +1,18 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + QObject::connect( + &engine, + &QQmlApplicationEngine::objectCreationFailed, + &app, + []() { QCoreApplication::exit(-1); }, + Qt::QueuedConnection); + engine.loadFromModule("WaterLevelRewrite", "Main"); + + return QCoreApplication::exec(); +} diff --git a/requestworker.cpp b/requestworker.cpp new file mode 100644 index 0000000..eff8079 --- /dev/null +++ b/requestworker.cpp @@ -0,0 +1,112 @@ +#include "requestworker.h" +#include +#include +#include +#include + +RequestWorker::RequestWorker(QObject *parent) + : QObject{parent} +{ + +} + +void RequestWorker::setConfig(QJsonObject config) +{ + this->url = config["url"].toString(); + this->interval = config["interval"].toInt(); + this->max_height = config["max"].toInt(); + this->min_height = config["min"].toInt(); + qDebug() << "In cpp config values are: "; + qDebug() << "Url: " << url; + qDebug() << "Interval: " << interval; + qDebug() << "Max Height: " << max_height; + qDebug() << "Min Height: " << min_height; +} + +void RequestWorker::start() +{ + if(manager) { + manager->deleteLater(); + manager = nullptr; + } + manager = new QNetworkAccessManager(); + if(timer) { + timer->deleteLater(); + timer = nullptr; + } + timer = new QTimer(this); + timer->setInterval(interval); + timer->setSingleShot(true); + connect(timer, &QTimer::timeout, this, &RequestWorker::makeRequest); + timer->start(); + stop_timer = false; + setStatus("Waiting to send."); +} + +void RequestWorker::stop() +{ + if(timer->isActive()) + timer->stop(); + stop_timer = true; +} + +void RequestWorker::makeRequest() +{ + if(stop_timer) + return; + QNetworkRequest req; + req.setUrl(this->url); + disconnect(manager, nullptr, nullptr, nullptr); + connect(manager, &QNetworkAccessManager::finished, this, &RequestWorker::requestFinished); + manager->setTransferTimeout(15000); + manager->get(req); + setStatus("Request sent; Waiting for Reply."); +} + +void RequestWorker::requestFinished(QNetworkReply *rep) +{ + QByteArray data = rep->readAll(); + rep->deleteLater(); + rep = nullptr; + auto now = std::chrono::high_resolution_clock::now(); + auto time_diff = std::chrono::duration_cast(now - prev_time); + unsigned int time_in_microseconds = time_diff.count(); + QJsonObject jdata = QJsonDocument::fromJson(data).object(); + auto data_water_level = jdata["water_level"].toInt(); + float water_level = (float) ((float) (data_water_level) / 10.0); + float rate_of_fill = ( float )(water_level - prev_distance) /(float) time_in_microseconds; + rate_of_fill = rate_of_fill * 1'000'000; + int expected_to_fill = (max_height - water_level) / rate_of_fill; + if(reply_number == 0) { + rate_of_fill = 0; + expected_to_fill = 0; + } + reply_number = 1; + qDebug() << "Got water level: " << water_level; + qDebug() << "Got rate of fill: " << rate_of_fill; + qDebug() << "Got expected to fill: " << expected_to_fill; + qDebug() << "Time difference: " << time_in_microseconds; + prev_distance = water_level; + emit networkReply(water_level, rate_of_fill, expected_to_fill); + if(stop_timer) { + setStatus("Timer stopped."); + return; + } + prev_time = now; + timer->start(); + QString status = "Got Reply on: " + QDateTime::currentDateTime().toString("hh:mm:ss") + "; Waiting to Send."; + setStatus(status); +} + +QString RequestWorker::status() const +{ + return m_status; +} + +void RequestWorker::setStatus(const QString &newStatus) +{ + if (m_status == newStatus) + return; + m_status = newStatus; + emit statusChanged(); +} diff --git a/requestworker.h b/requestworker.h new file mode 100644 index 0000000..05fbafa --- /dev/null +++ b/requestworker.h @@ -0,0 +1,49 @@ +#ifndef REQUESTWORKER_H +#define REQUESTWORKER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class RequestWorker : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QString status READ status WRITE setStatus NOTIFY statusChanged FINAL) + QNetworkAccessManager *manager = nullptr; + QTimer *timer = nullptr; + QString url; + int interval; + float prev_distance = 0; + int max_height = 0; + int min_height = 0; + bool stop_timer = false; + int reply_number = 0; + std::chrono::time_point prev_time; +public: + explicit RequestWorker(QObject *parent = nullptr); + + QString status() const; + void setStatus(const QString &newStatus); + +signals: + void networkReply(float distance, float rate_of_fill, int expected_to_fill); + void statusChanged(); + +public slots: + void setConfig(QJsonObject config); + void start(); + void stop(); +private slots: + void makeRequest(); + void requestFinished(QNetworkReply *rep); +private: + QString m_status; +}; + +#endif // REQUESTWORKER_H