v0.0.9
This commit is contained in:
parent
f59704545b
commit
69086d8093
10 changed files with 370 additions and 134 deletions
|
|
@ -5,9 +5,9 @@ project(waterLevelSensor VERSION 0.1 LANGUAGES CXX)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Quick Network)
|
find_package(Qt6 REQUIRED COMPONENTS Quick Network CorePrivate)
|
||||||
|
|
||||||
qt_standard_project_setup(REQUIRES 6.9)
|
qt_standard_project_setup(REQUIRES 6.11)
|
||||||
|
|
||||||
qt_add_executable(appwaterLevelSensor
|
qt_add_executable(appwaterLevelSensor
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
@ -41,8 +41,8 @@ set_property(TARGET service APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||||
target_link_libraries(service
|
target_link_libraries(service
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Qt::Core
|
Qt::Core
|
||||||
Qt::CorePrivate
|
|
||||||
Qt::Network
|
Qt::Network
|
||||||
|
Qt::CorePrivate
|
||||||
Qt::Quick
|
Qt::Quick
|
||||||
)
|
)
|
||||||
qt_add_qml_module(appwaterLevelSensor
|
qt_add_qml_module(appwaterLevelSensor
|
||||||
|
|
|
||||||
30
Main.qml
30
Main.qml
|
|
@ -634,11 +634,18 @@ Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timer {
|
Timer {
|
||||||
|
property int count: 0
|
||||||
id: init_timer
|
id: init_timer
|
||||||
running: true
|
running: true
|
||||||
repeat: false
|
repeat: true
|
||||||
interval: 1000
|
interval: 1000
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
|
if(count === 0) {
|
||||||
|
listener.startService();
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
console.log("Timer triggered saving config, hope everything is loaded by now");
|
console.log("Timer triggered saving config, hope everything is loaded by now");
|
||||||
let current_min_reading = Math.max(0, (parseFloat(min_thres_input.text)));
|
let current_min_reading = Math.max(0, (parseFloat(min_thres_input.text)));
|
||||||
let effective_max_reading = Math.max(0, (parseFloat(max_thres_input.text)) - current_min_reading);
|
let effective_max_reading = Math.max(0, (parseFloat(max_thres_input.text)) - current_min_reading);
|
||||||
|
|
@ -647,6 +654,9 @@ Window {
|
||||||
console.log("Setting initial configs: ", alert_effective_reading, config.flipBits , config.mode, config.url);
|
console.log("Setting initial configs: ", alert_effective_reading, config.flipBits , config.mode, config.url);
|
||||||
listener.setConfig(alert_effective_reading, config.flipBits , config.mode, config.url);
|
listener.setConfig(alert_effective_reading, config.flipBits , config.mode, config.url);
|
||||||
http_url_input.cursorPosition = 0;
|
http_url_input.cursorPosition = 0;
|
||||||
|
init_timer.repeat = false;
|
||||||
|
init_timer.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -658,9 +668,18 @@ Window {
|
||||||
error_text.error_string = err;
|
error_text.error_string = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
onLastUpdatedChanged: (update) => {
|
onLastUpdatedChanged: (update, warn) => {
|
||||||
console.log("QML Last Updated: ", update);
|
console.log("QML Last Updated: ", update);
|
||||||
|
if(!warn)
|
||||||
|
{
|
||||||
last_updated_text.last_updated = update;
|
last_updated_text.last_updated = update;
|
||||||
|
last_updated_text.color = root.accent_color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last_updated_text.last_updated = update;
|
||||||
|
last_updated_text.color = root.danger_color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDistanceChanged: {
|
onDistanceChanged: {
|
||||||
|
|
@ -722,9 +741,12 @@ Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosing:(close)=> {
|
onClosing: (close)=> {
|
||||||
if(Qt.platform.os === "android"){
|
if(Qt.platform.os === "android"){
|
||||||
close.accepted = false
|
// close.accepted = false
|
||||||
|
// listener.moveAppToBackground();
|
||||||
|
// console.log("Moving to backgound");
|
||||||
|
close.accepted = true;
|
||||||
} else {
|
} else {
|
||||||
close.accepted = true
|
close.accepted = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@
|
||||||
|
|
||||||
<service android:name=".WaterLevelService"
|
<service android:name=".WaterLevelService"
|
||||||
android:foregroundServiceType="connectedDevice"
|
android:foregroundServiceType="connectedDevice"
|
||||||
android:exported="true">
|
android:exported="true"
|
||||||
|
android:process=":water_service"
|
||||||
|
android:stopWithTask="false">
|
||||||
<!-- <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
<!-- <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||||
android:value="Monitoring water levels via local network UDP packets for real-time sensor alerts." />-->
|
android:value="Monitoring water levels via local network UDP packets for real-time sensor alerts." />-->
|
||||||
<meta-data android:name="android.app.lib_name" android:value="service"/>
|
<meta-data android:name="android.app.lib_name" android:value="service"/>
|
||||||
|
|
|
||||||
|
|
@ -32,22 +32,49 @@ public class WaterLevelService extends Service {
|
||||||
private boolean bits_flipped = false;
|
private boolean bits_flipped = false;
|
||||||
private String mode = "";
|
private String mode = "";
|
||||||
private String url = "";
|
private String url = "";
|
||||||
|
private Thread udpThread;
|
||||||
|
private Thread cmdThread;
|
||||||
|
private boolean resetBinds = false;
|
||||||
|
|
||||||
|
public synchronized boolean checkBound() {
|
||||||
|
return resetBinds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setBound(boolean value) {
|
||||||
|
resetBinds = value;
|
||||||
|
}
|
||||||
|
|
||||||
public class UDPCommandClient implements Runnable {
|
public class UDPCommandClient implements Runnable {
|
||||||
private DatagramSocket socket_cmd_recv;
|
private DatagramSocket socket_cmd_recv;
|
||||||
private DatagramSocket socket_cmd_send;
|
private DatagramSocket socket_cmd_send;
|
||||||
|
private boolean received_cmd_first = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.d("UDP Service", "Command thread initialising");
|
Log.d("UDP Service", "Command thread initialising");
|
||||||
try {
|
try {
|
||||||
socket_cmd_recv = new DatagramSocket(8178, InetAddress.getByName("localhost"));
|
socket_cmd_recv = new DatagramSocket(null);
|
||||||
socket_cmd_send = new DatagramSocket(8179);
|
socket_cmd_send = new DatagramSocket(null);
|
||||||
|
socket_cmd_recv.setSoTimeout(4000);
|
||||||
|
socket_cmd_recv.setReuseAddress(true);
|
||||||
|
socket_cmd_send.setReuseAddress(true);
|
||||||
|
socket_cmd_recv.bind(new InetSocketAddress(8178));
|
||||||
|
socket_cmd_send.bind(new InetSocketAddress(8179));
|
||||||
Log.d("UDP Service", "Created command thread sockets");
|
Log.d("UDP Service", "Created command thread sockets");
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
|
if(socket_cmd_recv.isClosed()) {
|
||||||
|
socket_cmd_recv.bind(new InetSocketAddress(8178));
|
||||||
|
}
|
||||||
|
if(socket_cmd_send.isClosed()) {
|
||||||
|
socket_cmd_send.bind(new InetSocketAddress(8179));
|
||||||
|
}
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
||||||
|
try {
|
||||||
socket_cmd_recv.receive(packet);
|
socket_cmd_recv.receive(packet);
|
||||||
|
} catch(java.net.SocketTimeoutException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String str = new String(buffer, StandardCharsets.UTF_8);
|
String str = new String(buffer, StandardCharsets.UTF_8);
|
||||||
Log.d("UDP Service ", "Received command packet " + str);
|
Log.d("UDP Service ", "Received command packet " + str);
|
||||||
if(str.startsWith("<SET NAME=ALERT VALUE=")) {
|
if(str.startsWith("<SET NAME=ALERT VALUE=")) {
|
||||||
|
|
@ -55,6 +82,17 @@ public class WaterLevelService extends Service {
|
||||||
str = str.replace("=", "");
|
str = str.replace("=", "");
|
||||||
str = str.replace(">", "");
|
str = str.replace(">", "");
|
||||||
alert_thres_distance = Float.parseFloat(str);
|
alert_thres_distance = Float.parseFloat(str);
|
||||||
|
{
|
||||||
|
if(!checkBound())
|
||||||
|
{
|
||||||
|
setBound(true);
|
||||||
|
Log.d("UDP Service ", "Set Bound to True");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.d("UDP Service ", "Set Bound is False");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(str.startsWith("<SET NAME=BITS_FLIPPED VALUE=")) {
|
else if(str.startsWith("<SET NAME=BITS_FLIPPED VALUE=")) {
|
||||||
str = str.replace("<SET NAME=BITS_FLIPPED VALUE=", "");
|
str = str.replace("<SET NAME=BITS_FLIPPED VALUE=", "");
|
||||||
|
|
@ -121,10 +159,14 @@ public class WaterLevelService extends Service {
|
||||||
multicastLock.acquire();
|
multicastLock.acquire();
|
||||||
wakeLock.acquire();
|
wakeLock.acquire();
|
||||||
wifiLock.acquire();
|
wifiLock.acquire();
|
||||||
socket_recv = new DatagramSocket(8176, InetAddress.getByName("0.0.0.0"));
|
socket_recv = new DatagramSocket(null);
|
||||||
socket_send = new DatagramSocket(8177);
|
socket_send = new DatagramSocket(null);
|
||||||
socket_recv.setBroadcast(true);
|
socket_recv.setBroadcast(true);
|
||||||
socket_recv.setSoTimeout(4000);
|
socket_recv.setSoTimeout(4000);
|
||||||
|
socket_recv.setReuseAddress(true);
|
||||||
|
socket_send.setReuseAddress(true);
|
||||||
|
socket_send.bind(new InetSocketAddress(8177));
|
||||||
|
socket_recv.bind(new InetSocketAddress(8176));
|
||||||
Log.d("UDP Service", "Created Sockets");
|
Log.d("UDP Service", "Created Sockets");
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
|
|
@ -133,10 +175,57 @@ public class WaterLevelService extends Service {
|
||||||
Log.i("UDP Service", "Thread is running with mode: " + mode);
|
Log.i("UDP Service", "Thread is running with mode: " + mode);
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
|
if(checkBound()) {
|
||||||
|
Log.i("UDP Service", "Reconnecting sockets");
|
||||||
|
socket_recv.close();
|
||||||
|
socket_send.close();
|
||||||
|
socket_recv = null;
|
||||||
|
socket_send = null;
|
||||||
|
socket_recv = new DatagramSocket(null);
|
||||||
|
socket_send = new DatagramSocket(null);
|
||||||
|
socket_recv.setBroadcast(true);
|
||||||
|
socket_recv.setSoTimeout(4000);
|
||||||
|
socket_recv.setReuseAddress(true);
|
||||||
|
socket_send.setReuseAddress(true);
|
||||||
|
socket_send.bind(new InetSocketAddress(8177));
|
||||||
|
socket_recv.bind(new InetSocketAddress(8176));
|
||||||
|
setBound(false);
|
||||||
|
Log.i("UDP Service", "Reconnected sockets");
|
||||||
|
}
|
||||||
|
// if(checkBound()) {
|
||||||
|
// Log.i("UDP Service", "Reset socket binds: " + mode);
|
||||||
|
// socket_recv.close();
|
||||||
|
// socket_send.close();
|
||||||
|
// socket_send.bind(new InetSocketAddress(8177));
|
||||||
|
// socket_recv.bind(new InetSocketAddress(8176));
|
||||||
|
// setBound(false);
|
||||||
|
// if(socket_send.isBound()) {
|
||||||
|
// Log.i("UDP Service", "Rebound socket: " + 8177);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// Log.i("UDP Service", "Failed to rebound socket: " + 8177);
|
||||||
|
// }
|
||||||
|
// if(socket_recv.isBound()) {
|
||||||
|
// Log.i("UDP Service", "Rebound socket: " + 8176);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// Log.i("UDP Service", "Failed to rebound socket: " + 8176);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// if(checkBound()) {
|
||||||
|
// Log.i("UDP Service", "Reset socket binds: " + mode);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// Log.i("UDP Service", "Reset socket binds: " + mode);
|
||||||
|
// }
|
||||||
byte[] buffer = null;
|
byte[] buffer = null;
|
||||||
String updated = "";
|
String updated = "";
|
||||||
if(mode.equals("udp")) {
|
if(mode.equals("udp")) {
|
||||||
try {
|
try {
|
||||||
|
if(socket_recv.isClosed()) {
|
||||||
|
socket_recv.bind(new InetSocketAddress(8176));
|
||||||
|
}
|
||||||
buffer = new byte[4];
|
buffer = new byte[4];
|
||||||
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
||||||
socket_recv.receive(packet);
|
socket_recv.receive(packet);
|
||||||
|
|
@ -227,6 +316,9 @@ public class WaterLevelService extends Service {
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(socket_send.isClosed()) {
|
||||||
|
socket_send.bind(new InetSocketAddress(8177));
|
||||||
|
}
|
||||||
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 8180);
|
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 8180);
|
||||||
socket_send.send(send_packet);
|
socket_send.send(send_packet);
|
||||||
Log.d("UDP Service ", "Sent packet");
|
Log.d("UDP Service ", "Sent packet");
|
||||||
|
|
@ -289,14 +381,40 @@ public class WaterLevelService extends Service {
|
||||||
Notification notification = createNotification();
|
Notification notification = createNotification();
|
||||||
startForeground(1, notification);
|
startForeground(1, notification);
|
||||||
|
|
||||||
|
|
||||||
|
if (intent == null) {
|
||||||
|
Log.w("UDP Service", "Service restarted with null intent. Stopping to avoid crash.");
|
||||||
|
stopSelf();
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
|
new Thread(new
|
||||||
|
Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// Move your socket and thread starting logic here
|
||||||
|
if (udpThread == null || !udpThread.isAlive()) {
|
||||||
|
udpThread = new Thread(new UDPClient());
|
||||||
|
udpThread.start();
|
||||||
|
}
|
||||||
|
if (cmdThread == null || !cmdThread.isAlive()) {
|
||||||
|
cmdThread = new Thread(new UDPCommandClient());
|
||||||
|
cmdThread.start();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("UDP Service", "Error starting threads", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
Log.d("UDP Service", "Actually starting the thread");
|
Log.d("UDP Service", "Actually starting the thread");
|
||||||
|
|
||||||
int ret = super.onStartCommand(intent, flags, startId);
|
int ret = super.onStartCommand(intent, flags, startId);
|
||||||
|
|
||||||
(new Thread(new UDPClient())).start();
|
// (new Thread(new UDPClient())).start();
|
||||||
(new Thread(new UDPCommandClient())).start();
|
// (new Thread(new UDPCommandClient())).start();
|
||||||
|
|
||||||
return START_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showToast(String str) {
|
public void showToast(String str) {
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,56 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityManager.RunningServiceInfo;
|
||||||
import org.qtproject.qt.android.bindings.QtActivity;
|
import org.qtproject.qt.android.bindings.QtActivity;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
public class WaterLevelServiceStarter {
|
public class WaterLevelServiceStarter {
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean isMyServiceRunning(Class<?> serviceClass, Context context) {
|
||||||
|
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||||
|
if (serviceClass.getName().equals(service.service.getClassName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getServicePid(Class<?> serviceClass, Context context) {
|
||||||
|
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||||
|
if (serviceClass.getName().equals(service.service.getClassName())) {
|
||||||
|
return service.pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static void startService(Context context) {
|
public static void startService(Context context) {
|
||||||
Log.d("UDP Service", "Starting service via QtActivity instance");
|
// Log.d("UDP Service", "Starting service via QtActivity instance");
|
||||||
|
|
||||||
|
// if(!isMyServiceRunning(WaterLevelService.class, context)) {
|
||||||
|
// Intent intent = new Intent(context, WaterLevelService.class);
|
||||||
|
// context.startForegroundService(intent);
|
||||||
|
// }
|
||||||
|
|
||||||
|
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!isMyServiceRunning(WaterLevelService.class, context)) {
|
||||||
|
Log.d("UDP Service", "Starting service safely on Main Looper");
|
||||||
Intent intent = new Intent(context, WaterLevelService.class);
|
Intent intent = new Intent(context, WaterLevelService.class);
|
||||||
|
|
||||||
context.startForegroundService(intent);
|
context.startForegroundService(intent);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Log.d("UDP Service", "Service already running");
|
||||||
|
}
|
||||||
|
Log.d("UDP Service", "Background service running with pid: " + getServicePid(WaterLevelService.class, context));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ ConfigInterface::ConfigInterface(QObject *parent)
|
||||||
QJsonObject top = QJsonDocument::fromJson(data).object();
|
QJsonObject top = QJsonDocument::fromJson(data).object();
|
||||||
QString max, min, alert, mode, url;
|
QString max, min, alert, mode, url;
|
||||||
bool flipbits;
|
bool flipbits;
|
||||||
max = top["max_threshold"].toString("100");
|
max = top["max_threshold"].toString("110");
|
||||||
min = top["min_threshold"].toString("20");
|
min = top["min_threshold"].toString("10");
|
||||||
alert = top["alert_threshold"].toString("60");
|
alert = top["alert_threshold"].toString("30");
|
||||||
flipbits = top["flip_bits"].toBool(true);
|
flipbits = top["flip_bits"].toBool(true);
|
||||||
mode = top["mode"].toString("http");
|
mode = top["mode"].toString("http");
|
||||||
url = top["url"].toString("https://unrealdragon.in/server/waterlevel");
|
url = top["url"].toString("https://unrealdragon.in/server/waterlevel");
|
||||||
|
|
@ -39,9 +39,9 @@ ConfigInterface::ConfigInterface(QObject *parent)
|
||||||
else {
|
else {
|
||||||
qDebug() << "File does not exist creating one...";
|
qDebug() << "File does not exist creating one...";
|
||||||
QJsonObject top;
|
QJsonObject top;
|
||||||
top["max_threshold"] = "125";
|
top["max_threshold"] = "110";
|
||||||
top["min_threshold"] = "25";
|
top["min_threshold"] = "10";
|
||||||
top["alert_threshold"] = "100";
|
top["alert_threshold"] = "30";
|
||||||
top["flip_bits"] = true;
|
top["flip_bits"] = true;
|
||||||
top["mode"] = "http";
|
top["mode"] = "http";
|
||||||
top["url"] = "https://unrealdragon.in/server/waterlevel";
|
top["url"] = "https://unrealdragon.in/server/waterlevel";
|
||||||
|
|
@ -54,9 +54,9 @@ ConfigInterface::ConfigInterface(QObject *parent)
|
||||||
config.write(data);
|
config.write(data);
|
||||||
config.flush();
|
config.flush();
|
||||||
config.close();
|
config.close();
|
||||||
setMax("125");
|
setMax("110");
|
||||||
setMin("25");
|
setMin("10");
|
||||||
setAlert("100");
|
setAlert("30");
|
||||||
setFlipBits(true);
|
setFlipBits(true);
|
||||||
setMode("http");
|
setMode("http");
|
||||||
setUrl("https://unrealdragon.in/server/waterlevel");
|
setUrl("https://unrealdragon.in/server/waterlevel");
|
||||||
|
|
|
||||||
137
service.cpp
137
service.cpp
|
|
@ -11,7 +11,6 @@
|
||||||
Q_DECLARE_JNI_CLASS(ComponentName, "android/content/ComponentName")
|
Q_DECLARE_JNI_CLASS(ComponentName, "android/content/ComponentName")
|
||||||
Q_DECLARE_JNI_CLASS(WaterLevelService, "org/qtproject/example/appwaterLevelSensor/WaterLevelService")
|
Q_DECLARE_JNI_CLASS(WaterLevelService, "org/qtproject/example/appwaterLevelSensor/WaterLevelService")
|
||||||
|
|
||||||
|
|
||||||
static volatile float level = -1;
|
static volatile float level = -1;
|
||||||
|
|
||||||
static void handleWaterLevelUpdate(JNIEnv *env, jobject /*obj*/, jbyteArray data) {
|
static void handleWaterLevelUpdate(JNIEnv *env, jobject /*obj*/, jbyteArray data) {
|
||||||
|
|
@ -29,87 +28,95 @@ static void handleWaterLevelUpdate(JNIEnv *env, jobject /*obj*/, jbyteArray data
|
||||||
env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
|
env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
|
JNIEnv* env;
|
||||||
|
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register your native method ONCE when the library loads
|
||||||
|
jclass javaClass = env->FindClass("org/qtproject/example/appwaterLevelSensor/WaterLevelReceiver");
|
||||||
|
if (javaClass) {
|
||||||
|
static JNINativeMethod methods[] = {
|
||||||
|
{"updateWaterLevel", "([B)V", (void *)handleWaterLevelUpdate}
|
||||||
|
};
|
||||||
|
env->RegisterNatives(javaClass, methods, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
service::service(QObject *parent)
|
service::service(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
{
|
{
|
||||||
if(QSysInfo::productType() == "android") {
|
if(QSysInfo::productType() == "android") {
|
||||||
qDebug() << "Running android service";
|
qDebug() << "Running android service";
|
||||||
|
// QJniEnvironment env;
|
||||||
|
// // if (env->ExceptionCheck()) env->ExceptionClear();
|
||||||
|
// // static bool nativesRegistered = false;
|
||||||
|
|
||||||
using namespace QtJniTypes;
|
// // if(!nativesRegistered) {
|
||||||
using namespace QNativeInterface;
|
// // // jclass javaClass = env.findClass("org/qtproject/example/appwaterLevelSensor/WaterLevelReceiver");
|
||||||
|
// // // if (javaClass) {
|
||||||
|
// // // JNINativeMethod methods[] = {{"updateWaterLevel", "([B)V", (void *)handleWaterLevelUpdate}};
|
||||||
|
// // // if (env->RegisterNatives(javaClass, methods, 1) < 0) {
|
||||||
|
// // // qDebug() << "RegisterNatives failed!";
|
||||||
|
// // // } else {
|
||||||
|
// // // nativesRegistered = true;
|
||||||
|
// // // }
|
||||||
|
// // // } else {
|
||||||
|
// // // qDebug() << "Could not find WaterLevelReceiver class";
|
||||||
|
// // // }
|
||||||
|
// // // if (env->ExceptionCheck()) env->ExceptionClear();
|
||||||
|
// // }
|
||||||
|
// using namespace QtJniTypes;
|
||||||
|
// using namespace QNativeInterface;
|
||||||
|
|
||||||
|
|
||||||
JNINativeMethod methods[] = {
|
|
||||||
{"updateWaterLevel", "([B)V", (void *)handleWaterLevelUpdate}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
|
// auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
|
||||||
// Context context = androidApp->context();
|
// // Context context = androidApp->context();
|
||||||
QJniObject context = QNativeInterface::QAndroidApplication::context();
|
// QJniObject context = QNativeInterface::QAndroidApplication::context();
|
||||||
|
// auto serviceClass = env.findClass(Traits<WaterLevelService>::className());
|
||||||
QJniEnvironment env;
|
// if (!serviceClass) {
|
||||||
auto serviceClass = env.findClass(Traits<WaterLevelService>::className());
|
// qDebug() << "FAILED to find WaterLevelService class!";
|
||||||
if (!serviceClass) {
|
// env->ExceptionDescribe(); // VERY important
|
||||||
qDebug() << "FAILED to find WaterLevelService class!";
|
// env->ExceptionClear();
|
||||||
env->ExceptionDescribe(); // VERY important
|
// return;
|
||||||
env->ExceptionClear();
|
// }
|
||||||
return;
|
// if (context.isValid()) {
|
||||||
|
// QJniObject::callStaticMethod<
|
||||||
|
// void>(
|
||||||
|
// "org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter",
|
||||||
|
// "startService",
|
||||||
|
// "(Landroid/content/Context;)V",
|
||||||
|
// context.object<jobject>());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jclass javaClass = env.findClass("org/qtproject/example/appwaterLevelSensor/WaterLevelReceiver");
|
void service::moveAppToBackground()
|
||||||
env->RegisterNatives(javaClass, methods, 1);
|
{
|
||||||
|
QJniObject activity = QNativeInterface::QAndroidApplication::context();
|
||||||
|
if (activity.isValid()) {
|
||||||
|
qDebug() << "Moved app to background";
|
||||||
|
activity.callMethod<jboolean>("moveTaskToBack", "(Z)Z", true);
|
||||||
|
}
|
||||||
|
qDebug() << "Closing";
|
||||||
|
}
|
||||||
|
|
||||||
|
void service::begin() {
|
||||||
|
|
||||||
|
|
||||||
|
// Only call this once the UI is visible
|
||||||
|
QJniObject context = QNativeInterface::QAndroidApplication::context();
|
||||||
QJniObject::callStaticMethod<void>(
|
QJniObject::callStaticMethod<void>(
|
||||||
"org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter",
|
"org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter",
|
||||||
"startService",
|
"startService",
|
||||||
"(Landroid/content/Context;)V",
|
"(Landroid/content/Context;)V",
|
||||||
context.object<jobject>()); // pass the QtActivity instance );
|
context.object<jobject>()
|
||||||
|
);
|
||||||
// QJniObject activity = QNativeInterface::QAndroidApplication::context();
|
|
||||||
// activity.callMethod<void>("startWaterLevelService", "()V");
|
|
||||||
// Intent serviceIntent(activity, serviceClass);
|
|
||||||
// activity.callMethod<WaterLevelService>("startWaterLevelService");
|
|
||||||
|
|
||||||
// activity.callMethod<()
|
|
||||||
// QJniObject::callStaticMethod<void>(
|
|
||||||
// "org/qtproject/example/appwaterLevelSensor/WaterLevelService",
|
|
||||||
// "startQtAndroidService",
|
|
||||||
// "(Landroid/content/Context;)V",
|
|
||||||
// activity.object<jobject>()
|
|
||||||
// );
|
|
||||||
|
|
||||||
// activity.callMethod<void>("startWaterLevelService", "()V"); // Intent serviceIntent(context, serviceClass);
|
|
||||||
// context.callMethod<ComponentName>("startService", serviceIntent);
|
|
||||||
|
|
||||||
// context.callMethod<ComponentName>(
|
|
||||||
// "startForegroundService",
|
|
||||||
// serviceIntent
|
|
||||||
// );
|
|
||||||
// QJniObject className = QJniObject::fromString(
|
|
||||||
// "org.qtproject.example.appwaterLevelSensor.WaterLevelService"
|
|
||||||
// );
|
|
||||||
|
|
||||||
// QJniObject serviceClassObj = QJniObject::callStaticObjectMethod(
|
|
||||||
// "java/lang/Class",
|
|
||||||
// "forName",
|
|
||||||
// "(Ljava/lang/String;)Ljava/lang/Class;",
|
|
||||||
// className.object<jstring>()
|
|
||||||
// );
|
|
||||||
|
|
||||||
// QJniObject intent(
|
|
||||||
// "android/content/Intent",
|
|
||||||
// "(Landroid/content/Context;Ljava/lang/Class;)V",
|
|
||||||
// context.object(),
|
|
||||||
// serviceClassObj.object()
|
|
||||||
// );
|
|
||||||
|
|
||||||
// context.callObjectMethod(
|
|
||||||
// "startForegroundService",
|
|
||||||
// "(Landroid/content/Intent;)Landroid/content/ComponentName;",
|
|
||||||
// intent.object()
|
|
||||||
// ); // WaterLevelService::callStaticMethod<void>("startQtAndroidService", context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ class service : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit service(QObject *parent = nullptr);
|
explicit service(QObject *parent = nullptr);
|
||||||
|
void moveAppToBackground();
|
||||||
|
void begin();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
#include "udplistener.h"
|
#include "udplistener.h"
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
#include "service.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UDPListener::UDPListener(QObject *parent)
|
UDPListener::UDPListener(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
{
|
{
|
||||||
worker = new Worker(this);
|
worker = new Worker();
|
||||||
thread = new QThread(this);
|
thread = new QThread();
|
||||||
worker->moveToThread(thread);
|
worker->moveToThread(thread);
|
||||||
connect(worker, &Worker::lastUpdateddatagramReceived, this, &UDPListener::lastUpdateddatagramReceived);
|
connect(worker, &Worker::lastUpdateddatagramReceived, this, &UDPListener::lastUpdateddatagramReceived);
|
||||||
connect(worker, &Worker::datagramReceived, this, &UDPListener::datagramRecieved);
|
connect(worker, &Worker::datagramReceived, this, &UDPListener::datagramRecieved);
|
||||||
|
|
@ -23,11 +20,6 @@ UDPListener::UDPListener(QObject *parent)
|
||||||
timer->setSingleShot(false);
|
timer->setSingleShot(false);
|
||||||
connect(timer, &QTimer::timeout, this, &UDPListener::connectionTimerTimedOut);
|
connect(timer, &QTimer::timeout, this, &UDPListener::connectionTimerTimedOut);
|
||||||
connect(qApp, &QCoreApplication::aboutToQuit, this, &UDPListener::destroy);
|
connect(qApp, &QCoreApplication::aboutToQuit, this, &UDPListener::destroy);
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
qDebug() << "Running on Android";
|
|
||||||
service service;
|
|
||||||
qDebug() << "Ran service";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double UDPListener::distance() const
|
double UDPListener::distance() const
|
||||||
|
|
@ -41,11 +33,29 @@ void UDPListener::setDistance(double newDistance)
|
||||||
emit distanceChanged();
|
emit distanceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDPListener::moveAppToBackground()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
service->moveAppToBackground();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void UDPListener::lastUpdateddatagramReceived(QByteArray data)
|
void UDPListener::lastUpdateddatagramReceived(QByteArray data)
|
||||||
{
|
{
|
||||||
QString s_data = QString::fromUtf8(data);
|
QString s_data = QString::fromUtf8(data);
|
||||||
qDebug() << "Main Class last updated on: " << s_data;
|
qDebug() << "Main Class last updated on: " << s_data;
|
||||||
emit lastUpdatedChanged(s_data);
|
QDateTime time = QDateTime::fromString(s_data, "dd/MM/yy hh:mm:ss");
|
||||||
|
QDateTime thres_time = QDateTime::currentDateTime().addSecs(-1800);
|
||||||
|
if(time.isValid() && time < thres_time)
|
||||||
|
{
|
||||||
|
emit lastUpdatedChanged(s_data, false);
|
||||||
|
}
|
||||||
|
else if(time > thres_time && time.isValid()) {
|
||||||
|
emit lastUpdatedChanged(s_data, true);
|
||||||
|
}
|
||||||
|
else if(!time.isValid()) {
|
||||||
|
emit lastUpdatedChanged("Invalid Date", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPListener::continueDestruction()
|
void UDPListener::continueDestruction()
|
||||||
|
|
@ -114,6 +124,9 @@ void UDPListener::setConfig(float distance, bool flip_bits, QString mode, QStrin
|
||||||
|
|
||||||
emit changeWorkerMode(mode, url);
|
emit changeWorkerMode(mode, url);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
showError("Command Socket Bind Failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
averages.clear();
|
averages.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -129,6 +142,12 @@ void UDPListener::socketError(QString err)
|
||||||
|
|
||||||
void UDPListener::startService()
|
void UDPListener::startService()
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
qDebug() << "Running on Android";
|
||||||
|
service = new class service();
|
||||||
|
qDebug() << "Ran service";
|
||||||
|
service->begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,25 +182,31 @@ void UDPListener::datagramRecieved(QByteArray data1, QByteArray data2)
|
||||||
void UDPListener::destroy()
|
void UDPListener::destroy()
|
||||||
{
|
{
|
||||||
qDebug() << "Destroying UDP Listener";
|
qDebug() << "Destroying UDP Listener";
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
delete service;
|
||||||
|
#endif
|
||||||
|
disconnect(timer, nullptr, nullptr, nullptr);
|
||||||
timer->stop();
|
timer->stop();
|
||||||
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
connect(this, &UDPListener::stopWorker, worker, &Worker::stop);
|
connect(this, &UDPListener::stopWorker, worker, &Worker::stop);
|
||||||
connect(worker, &Worker::stopped, this, &UDPListener::continueDestruction);
|
connect(worker, &Worker::stopped, this, &UDPListener::continueDestruction);
|
||||||
emit stopWorker();
|
emit stopWorker();
|
||||||
while(!destroyed) {
|
while(!destroyed) {
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
}
|
}
|
||||||
thread->exit(0);
|
thread->exit(0);
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
QCoreApplication::processEvents();
|
|
||||||
worker->deleteLater();
|
worker->deleteLater();
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
QCoreApplication::processEvents();
|
while(thread->isRunning()) {
|
||||||
|
qDebug() << "The thread is still running.";
|
||||||
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
|
}
|
||||||
thread->deleteLater();
|
thread->deleteLater();
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
QCoreApplication::processEvents();
|
|
||||||
timer->deleteLater();
|
timer->deleteLater();
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
||||||
QCoreApplication::processEvents();
|
|
||||||
qDebug() << "Deinitialized UDP Listener";
|
qDebug() << "Deinitialized UDP Listener";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,6 +259,7 @@ void Worker::gotHttpReply(QNetworkReply *rep)
|
||||||
|
|
||||||
void Worker::httpTimerTimeout()
|
void Worker::httpTimerTimeout()
|
||||||
{
|
{
|
||||||
|
qDebug() << "Worker httpTimer Timeout";
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
req.setUrl(QUrl("https://unrealdragon.in/server/waterlevel"));
|
req.setUrl(QUrl("https://unrealdragon.in/server/waterlevel"));
|
||||||
disconnect(manager, nullptr, nullptr, nullptr);
|
disconnect(manager, nullptr, nullptr, nullptr);
|
||||||
|
|
@ -243,8 +269,16 @@ void Worker::httpTimerTimeout()
|
||||||
|
|
||||||
void Worker::stop()
|
void Worker::stop()
|
||||||
{
|
{
|
||||||
|
if(socket_2) {
|
||||||
|
disconnect(socket_2, nullptr, nullptr, nullptr);
|
||||||
|
socket_2->close();
|
||||||
|
delete socket_2;
|
||||||
|
}
|
||||||
|
if(socket) {
|
||||||
disconnect(socket, nullptr, nullptr, nullptr);
|
disconnect(socket, nullptr, nullptr, nullptr);
|
||||||
|
socket->close();
|
||||||
delete socket;
|
delete socket;
|
||||||
|
}
|
||||||
if(httpTimer) {
|
if(httpTimer) {
|
||||||
disconnect(httpTimer, nullptr, nullptr, nullptr);
|
disconnect(httpTimer, nullptr, nullptr, nullptr);
|
||||||
delete httpTimer;
|
delete httpTimer;
|
||||||
|
|
@ -265,8 +299,8 @@ void Worker::run()
|
||||||
manager = new QNetworkAccessManager(this);
|
manager = new QNetworkAccessManager(this);
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
// If it is android use it as a command socket;
|
// If it is android use it as a command socket;
|
||||||
bool bind = socket->bind(QHostAddress::Any, 8180);
|
bool bind = socket->bind(QHostAddress::Any, 8180, QUdpSocket::ReuseAddressHint);
|
||||||
bool bind2 = socket_2->bind(QHostAddress::Any, 8185);
|
bool bind2 = socket_2->bind(QHostAddress::Any, 8185, QUdpSocket::ReuseAddressHint);
|
||||||
#else
|
#else
|
||||||
// Else use it as a receiver;
|
// Else use it as a receiver;
|
||||||
bool bind = socket->bind(QHostAddress("192.168.1.255"), 8176);
|
bool bind = socket->bind(QHostAddress("192.168.1.255"), 8176);
|
||||||
|
|
@ -277,6 +311,7 @@ void Worker::run()
|
||||||
qDebug() << "UI Worker socket bind failed" << bind << socket->errorString();
|
qDebug() << "UI Worker socket bind failed" << bind << socket->errorString();
|
||||||
emit socketError(socket->errorString());
|
emit socketError(socket->errorString());
|
||||||
emit socketError(socket_2->errorString());
|
emit socketError(socket_2->errorString());
|
||||||
|
qApp->exit(-1);
|
||||||
}
|
}
|
||||||
connect(httpTimer, &QTimer::timeout, this, &Worker::httpTimerTimeout);
|
connect(httpTimer, &QTimer::timeout, this, &Worker::httpTimerTimeout);
|
||||||
connect(socket, &QUdpSocket::readyRead, this, &Worker::socketDataReceived);
|
connect(socket, &QUdpSocket::readyRead, this, &Worker::socketDataReceived);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include "moving_container.h"
|
#include "moving_container.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
#include "service.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class Worker: public QObject {
|
class Worker: public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QUdpSocket *socket = nullptr;
|
QUdpSocket *socket = nullptr;
|
||||||
|
|
@ -48,12 +53,15 @@ class UDPListener : public QObject
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
Q_PROPERTY(double distance READ distance WRITE setDistance NOTIFY distanceChanged FINAL)
|
Q_PROPERTY(double distance READ distance WRITE setDistance NOTIFY distanceChanged FINAL)
|
||||||
bool destroyed = false;
|
bool destroyed = false;
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
service *service = nullptr;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
explicit UDPListener(QObject *parent = nullptr);
|
explicit UDPListener(QObject *parent = nullptr);
|
||||||
double distance() const;
|
double distance() const;
|
||||||
void setDistance(double newDistance);
|
void setDistance(double newDistance);
|
||||||
signals:
|
signals:
|
||||||
void lastUpdatedChanged(QString last_updated);
|
void lastUpdatedChanged(QString last_updated, bool warn);
|
||||||
void stopWorker();
|
void stopWorker();
|
||||||
void showError(QString err);
|
void showError(QString err);
|
||||||
void distanceChanged();
|
void distanceChanged();
|
||||||
|
|
@ -63,6 +71,7 @@ signals:
|
||||||
void distanceReceived(double dist, QString timestamp);
|
void distanceReceived(double dist, QString timestamp);
|
||||||
void changeWorkerMode(QString mode, QString url);
|
void changeWorkerMode(QString mode, QString url);
|
||||||
public slots:
|
public slots:
|
||||||
|
void moveAppToBackground();
|
||||||
void lastUpdateddatagramReceived(QByteArray data);
|
void lastUpdateddatagramReceived(QByteArray data);
|
||||||
void continueDestruction();
|
void continueDestruction();
|
||||||
void resetAverages();
|
void resetAverages();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue