WaterLevelSensor/requestworker.cpp

297 lines
8.7 KiB
C++
Raw Normal View History

2026-08-04 21:31:40 +05:30
#include "requestworker.h"
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonDocument>
2026-08-12 18:22:15 +05:30
#include <QFile>
2026-09-23 17:36:00 +05:30
#include <QStandardPaths>
2026-08-04 21:31:40 +05:30
RequestWorker::RequestWorker(QObject *parent)
: QObject{parent}
{
2026-09-14 15:31:21 +05:30
#ifdef Q_OS_ANDROID
wifi = new WiFiHelper(this);
connect(wifi, &WiFiHelper::ssidRetrieved, this, &RequestWorker::gotWiFiSSID);
poll_wifi = new QTimer(this);
poll_wifi->setInterval(3000);
poll_wifi->setSingleShot(false);
connect(poll_wifi, &QTimer::timeout, this, &RequestWorker::pollWiFi);
wifi->requestPermissionsAndFetch();
poll_wifi->start();
#endif
2026-08-04 21:31:40 +05:30
}
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();
2026-08-12 18:22:15 +05:30
this->alarm_thres = config["alert"].toInt();
2026-08-04 21:31:40 +05:30
qDebug() << "In cpp config values are: ";
qDebug() << "Url: " << url;
qDebug() << "Interval: " << interval;
qDebug() << "Max Height: " << max_height;
qDebug() << "Min Height: " << min_height;
2026-08-12 18:22:15 +05:30
qDebug() << "Alert: " << alarm_thres;
2026-08-04 21:31:40 +05:30
}
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;
qDebug() << "Stopping" << timer->isActive();
2026-08-04 21:31:40 +05:30
}
2026-09-23 17:36:00 +05:30
QString RequestWorker::getRequestResponseString(QNetworkReply *rep, QString rep_data)
{
if(!rep) {
return "No Reply";
}
QNetworkRequest req = rep->request();
QString errorString = rep->errorString();
QString resp = "GET " + req.url().toString() + "\n";
for(auto &key: req.rawHeaderList()) {
QByteArray value = req.rawHeader(key);
resp += key + ": " + value + "\n";
}
qDebug() << "Raw header list size: " << req.rawHeaderList().size();
QString ret;
ret = "Request:\n";
ret += resp;
ret += "Response:\n";
if(rep_data == "")
ret += errorString;
else
ret += rep_data;
return ret;
}
2026-09-14 15:31:21 +05:30
void RequestWorker::pollWiFi()
{
#ifdef Q_OS_ANDROID
if(wifi) {
wifi->requestPermissionsAndFetch();
}
#endif
}
void RequestWorker::gotWiFiSSID(QString ssid)
{
if(ssid.length() > 0 && ssid != "Permission Denied" && ssid != "<unknown ssid>") {
emit connectionText("WiFi connected: " + ssid);
}
else if(ssid.length() == 0) {
emit connectionText("WiFi might not be connected", true);
}
else if(ssid != "<unknown ssid>") {
emit connectionText("Failed to query wifi info", true);
}
else {
emit connectionText("WiFi disconnected", true);
}
}
2026-08-12 18:22:15 +05:30
void RequestWorker::playAlarm()
{
2026-09-23 17:36:00 +05:30
if (player_started)
2026-08-12 18:22:15 +05:30
return;
2026-09-23 17:36:00 +05:30
// Step 1: Copy the qrc resource to a local cache file so Android can read it
#ifdef Q_OS_ANDROID
QString qrcPath = ":/sounds/echo.mp3";
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/echo.mp3";
if (QFile::exists(cachePath)) {
QFile::remove(cachePath);
}
if (QFile::copy(qrcPath, cachePath)) {
qDebug() << "Successfully copied resource to cache:" << cachePath;
} else {
qDebug() << "Failed to copy resource to cache path!";
return;
}
// Step 2: Use Android JNI to initialize and play via android.media.MediaPlayer
QJniEnvironment env;
// Create new android.media.MediaPlayer()
QJniObject mediaPlayer("android/media/MediaPlayer");
if (!mediaPlayer.isValid()) {
qDebug() << "Failed to create native Android MediaPlayer!";
return;
}
// Set data source using the local cache file path
QJniObject jPath = QJniObject::fromString(cachePath);
mediaPlayer.callMethod<void>("setDataSource", "(Ljava/lang/String;)V", jPath.object<jstring>());
// Enable looping
mediaPlayer.callMethod<void>("setLooping", "(Z)V", true);
// Prepare and start playback
mediaPlayer.callMethod<void>("prepare");
mediaPlayer.callMethod<void>("start");
// Store a global reference so it doesn't get garbage collected immediately
m_androidMediaPlayer = new QJniObject(mediaPlayer.object());
player_started = true;
qDebug() << "Native Android alarm started successfully.";
return;
#endif
2026-08-12 18:22:15 +05:30
if(player) {
player->deleteLater();
player = nullptr;
}
if(audioOutput) {
audioOutput->deleteLater();
audioOutput->deleteLater();
}
qDebug() << "Loading player";
player = new QMediaPlayer(this);
audioOutput = new QAudioOutput(this);
player->setLoops(QMediaPlayer::Loops::Infinite);
2026-08-12 18:22:15 +05:30
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();
}
2026-08-04 21:31:40 +05:30
void RequestWorker::makeRequest()
{
if(stop_timer)
return;
QNetworkRequest req;
2026-09-23 17:36:00 +05:30
req.setRawHeader("Testing", "Something");
2026-08-04 21:31:40 +05:30
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();
auto now = std::chrono::high_resolution_clock::now();
auto time_diff = std::chrono::duration_cast<std::chrono::microseconds>(now - prev_time);
if(data.size() == 0) {
prev_time = now;
timer->start();
2026-09-23 17:36:00 +05:30
QString request_response_string = getRequestResponseString(rep);
emit requestFailed(request_response_string);
emit setStatus("Invalid Response; Resending Request");
2026-09-23 17:36:00 +05:30
rep->deleteLater();
rep = nullptr;
return;
}
2026-08-04 21:31:40 +05:30
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 )(prev_distance - water_level) /(float) time_in_microseconds;
2026-08-04 21:31:40 +05:30
rate_of_fill = rate_of_fill * 1'000'000;
int expected_to_fill = (water_level - min_height) / rate_of_fill;
2026-09-23 17:36:00 +05:30
int percentage_filled = (float (max_height - water_level) / float (max_height)) * 100;
2026-08-12 18:22:15 +05:30
if(enable_alarm) {
qDebug() << "Alarm enabled";
2026-09-23 17:36:00 +05:30
if(water_level <= alarm_thres) {
2026-08-12 18:22:15 +05:30
playAlarm();
}
}
2026-08-04 21:31:40 +05:30
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;
2026-08-12 18:22:15 +05:30
qDebug() << "Percentage filled: " << percentage_filled;
2026-08-04 21:31:40 +05:30
qDebug() << "Time difference: " << time_in_microseconds;
prev_distance = water_level;
2026-09-23 17:36:00 +05:30
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
QString request_response_string = getRequestResponseString(rep, data);
request_response_string += "Timestamp:\n" + timestamp;
rep->deleteLater();
rep = nullptr;
emit networkReply(data_water_level, rate_of_fill, expected_to_fill, request_response_string);
2026-08-04 21:31:40 +05:30
if(stop_timer) {
setStatus("Timer stopped.");
return;
}
prev_time = now;
timer->start();
2026-09-23 17:36:00 +05:30
QString status = "Got Reply on: " + timestamp + "; Waiting to Send.";
2026-08-04 21:31:40 +05:30
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();
}
2026-08-12 18:22:15 +05:30
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;
}
2026-09-23 17:36:00 +05:30
#ifdef Q_OS_ANDROID
if(m_androidMediaPlayer) {
delete m_androidMediaPlayer;
m_androidMediaPlayer = nullptr;
}
#endif
2026-08-12 18:22:15 +05:30
}