Compare commits
13 changed files with 209 additions and 1406 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 CorePrivate)
|
find_package(Qt6 REQUIRED COMPONENTS Quick Network)
|
||||||
|
|
||||||
qt_standard_project_setup(REQUIRES 6.11)
|
qt_standard_project_setup(REQUIRES 6.9)
|
||||||
|
|
||||||
qt_add_executable(appwaterLevelSensor
|
qt_add_executable(appwaterLevelSensor
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
@ -16,22 +16,10 @@ qt_add_executable(appwaterLevelSensor
|
||||||
|
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
|
|
||||||
include(FetchContent)
|
|
||||||
FetchContent_Declare(
|
|
||||||
android_openssl
|
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP true
|
|
||||||
URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(android_openssl)
|
|
||||||
include(${android_openssl_SOURCE_DIR}/android_openssl.cmake)
|
|
||||||
|
|
||||||
qt_add_library(service SHARED
|
qt_add_library(service SHARED
|
||||||
servicemain.cpp
|
servicemain.cpp
|
||||||
service.h service.cpp
|
service.h service.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
set_property(TARGET appwaterLevelSensor APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
set_property(TARGET appwaterLevelSensor APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/android)
|
${CMAKE_CURRENT_SOURCE_DIR}/android)
|
||||||
set_property(TARGET service APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
set_property(TARGET service APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||||
|
|
@ -41,8 +29,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::Network
|
|
||||||
Qt::CorePrivate
|
Qt::CorePrivate
|
||||||
|
Qt::Network
|
||||||
Qt::Quick
|
Qt::Quick
|
||||||
)
|
)
|
||||||
qt_add_qml_module(appwaterLevelSensor
|
qt_add_qml_module(appwaterLevelSensor
|
||||||
|
|
@ -57,7 +45,6 @@ qt_add_qml_module(appwaterLevelSensor
|
||||||
SOURCES service.h
|
SOURCES service.h
|
||||||
RESOURCES README.md
|
RESOURCES README.md
|
||||||
)
|
)
|
||||||
add_android_openssl_libraries(service appwaterLevelSensor)
|
|
||||||
target_link_libraries(appwaterLevelSensor
|
target_link_libraries(appwaterLevelSensor
|
||||||
PRIVATE Qt6::Quick Qt6::Network service
|
PRIVATE Qt6::Quick Qt6::Network service
|
||||||
)
|
)
|
||||||
|
|
|
||||||
338
Main.qml
338
Main.qml
|
|
@ -6,62 +6,19 @@ import QtQuick.Controls.Material
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
width: 640
|
width: 640
|
||||||
height: 1080
|
height: 480
|
||||||
visible: true
|
visible: true
|
||||||
title: qsTr("Hello World")
|
title: qsTr("Hello World")
|
||||||
id: root
|
id: root
|
||||||
property color accent_color: "#F05FAF5F"
|
property color accent_color: "#F05FAF5F"
|
||||||
property color dark_accent_color: "#FF5F7F5F"
|
|
||||||
property color danger_color: "#F0AF2F1F"
|
property color danger_color: "#F0AF2F1F"
|
||||||
property color water_color: "#F00F7FAF"
|
property color water_color: "#F00F7FAF"
|
||||||
Material.accent: root.accent_color
|
Material.accent: root.accent_color
|
||||||
property int font_enlarged_text_size: 20
|
property int font_enlarged_text_size: 20
|
||||||
property int font_normal_text_size: 16
|
property int font_normal_text_size: 18
|
||||||
property double distance: 0
|
property double distance: 0
|
||||||
property int distance_count: 0
|
property int distance_count: 0
|
||||||
property int distance_count_thres: 3
|
|
||||||
property string mode: "http"
|
|
||||||
// visibility: Window.FullScreen
|
// visibility: Window.FullScreen
|
||||||
Component.onCompleted: {
|
|
||||||
loading_popup.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Popup {
|
|
||||||
id: loading_popup
|
|
||||||
background: Rectangle {
|
|
||||||
color: "#B0121212"
|
|
||||||
radius: 5
|
|
||||||
border.color: root.accent_color
|
|
||||||
border.width: 1
|
|
||||||
}
|
|
||||||
height: parent.height / 10
|
|
||||||
width: parent.width / 1.1
|
|
||||||
anchors.centerIn: Overlay.overlay
|
|
||||||
closePolicy: Popup.NoAutoClose
|
|
||||||
BusyIndicator {
|
|
||||||
id: loading_indicator
|
|
||||||
running: true
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
id: loading_text
|
|
||||||
text: "Loading..."
|
|
||||||
anchors {
|
|
||||||
leftMargin: 20
|
|
||||||
left: loading_indicator.right
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
color: root.accent_color
|
|
||||||
font.pointSize: root.font_enlarged_text_size
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
id: background
|
id: background
|
||||||
|
|
@ -188,8 +145,8 @@ Window {
|
||||||
border.color: root.accent_color
|
border.color: root.accent_color
|
||||||
border.width: 1
|
border.width: 1
|
||||||
}
|
}
|
||||||
height: Math.max(parent.height / 1.2, contentHeight)
|
height: parent.height / 1.5
|
||||||
width: parent.width / 1.1
|
width: parent.width / 1.5
|
||||||
anchors.centerIn: Overlay.overlay
|
anchors.centerIn: Overlay.overlay
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -219,26 +176,24 @@ Window {
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
top: settings_label.bottom
|
top: settings_label.bottom
|
||||||
left: parent.left
|
left: parent.left
|
||||||
verticalCenter: max_thres_input.verticalCenter
|
|
||||||
}
|
}
|
||||||
height: max_thres_input.height
|
height: max_thres_input.height
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pointSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: max_thres_input
|
id: max_thres_input
|
||||||
text: config.max
|
text: config.max
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
left: max_thres_label.right
|
||||||
rightMargin: 5
|
leftMargin: 5
|
||||||
top: settings_label.bottom
|
top: settings_label.bottom
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
}
|
}
|
||||||
width: parent.width / 2
|
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pointSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -249,26 +204,24 @@ Window {
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
top: max_thres_label.bottom
|
top: max_thres_label.bottom
|
||||||
left: parent.left
|
left: parent.left
|
||||||
verticalCenter: min_thres_input.verticalCenter
|
|
||||||
}
|
}
|
||||||
height: min_thres_input.height
|
height: min_thres_input.height
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pointSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: min_thres_input
|
id: min_thres_input
|
||||||
text: config.min
|
text: config.min
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
left: min_thres_label.right
|
||||||
rightMargin: 5
|
leftMargin: 5
|
||||||
top: max_thres_label.bottom
|
top: max_thres_label.bottom
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
}
|
}
|
||||||
width: parent.width / 2
|
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pointSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -279,132 +232,24 @@ Window {
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
top: min_thres_label.bottom
|
top: min_thres_label.bottom
|
||||||
left: parent.left
|
left: parent.left
|
||||||
verticalCenter: alert_thres_input.verticalCenter
|
|
||||||
}
|
}
|
||||||
height: alert_thres_input.height
|
height: alert_thres_input.height
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pointSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: alert_thres_input
|
id: alert_thres_input
|
||||||
text: config.alert
|
text: config.alert
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
left: alert_thres_label.right
|
||||||
rightMargin: 5
|
leftMargin: 5
|
||||||
top: min_thres_label.bottom
|
top: min_thres_label.bottom
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
}
|
}
|
||||||
width: parent.width / 2
|
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pointSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
id: flip_bits_box
|
|
||||||
text: "Flip Bits"
|
|
||||||
checked: config.flipBits
|
|
||||||
anchors {
|
|
||||||
topMargin: 20
|
|
||||||
top: alert_thres_label.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
contentItem: Text {
|
|
||||||
text: flip_bits_box.text
|
|
||||||
font.pointSize: root.font_normal_text_size
|
|
||||||
color: root.accent_color
|
|
||||||
leftPadding: flip_bits_box.indicator.width + flip_bits_box.spacing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: settings_mode_text
|
|
||||||
anchors {
|
|
||||||
topMargin: 20
|
|
||||||
top: flip_bits_box.bottom
|
|
||||||
left: parent.left
|
|
||||||
}
|
|
||||||
font.pointSize: root.font_normal_text_size
|
|
||||||
color: root.accent_color
|
|
||||||
text: "Mode: "
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
id: mode_row
|
|
||||||
anchors {
|
|
||||||
left: settings_mode_text.right
|
|
||||||
right: parent.right
|
|
||||||
verticalCenter: settings_mode_text.verticalCenter
|
|
||||||
leftMargin: 10
|
|
||||||
}
|
|
||||||
RadioButton {
|
|
||||||
id: udp_radio_button
|
|
||||||
checked: config.mode === "udp" ? true : false
|
|
||||||
text: "UDP"
|
|
||||||
font.pointSize: root.font_normal_text_size
|
|
||||||
contentItem: Text {
|
|
||||||
text: udp_radio_button.text
|
|
||||||
font: udp_radio_button.font
|
|
||||||
opacity: enabled ? 1.0 : 0.3
|
|
||||||
color: udp_radio_button.down ? root.dark_accent_color : root.accent_color
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
leftPadding: udp_radio_button.indicator.width + udp_radio_button.spacing
|
|
||||||
}
|
|
||||||
onCheckedChanged: {
|
|
||||||
if(checked) {
|
|
||||||
root.mode = "udp";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RadioButton {
|
|
||||||
id: http_radio_button
|
|
||||||
checked: config.mode === "http" ? true : false
|
|
||||||
text: "HTTP"
|
|
||||||
font.pointSize: root.font_normal_text_size
|
|
||||||
contentItem: Text {
|
|
||||||
text: http_radio_button.text
|
|
||||||
font: http_radio_button.font
|
|
||||||
opacity: enabled ? 1.0 : 0.3
|
|
||||||
color: http_radio_button.down ? root.dark_accent_color : root.accent_color
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
leftPadding: http_radio_button.indicator.width + http_radio_button.spacing
|
|
||||||
}
|
|
||||||
onCheckedChanged: {
|
|
||||||
if(checked) {
|
|
||||||
root.mode = "http";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
id: http_url_label
|
|
||||||
text: "Url: "
|
|
||||||
anchors {
|
|
||||||
topMargin: 20
|
|
||||||
top: settings_mode_text.bottom
|
|
||||||
left: parent.left
|
|
||||||
verticalCenter: http_url_input.verticalCenter
|
|
||||||
}
|
|
||||||
height: http_url_input.height
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
color: root.accent_color
|
|
||||||
font.pointSize: root.font_normal_text_size
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: http_url_input
|
|
||||||
text: config.url
|
|
||||||
anchors {
|
|
||||||
right: parent.right
|
|
||||||
rightMargin: 20
|
|
||||||
leftMargin: 20
|
|
||||||
top: mode_row.bottom
|
|
||||||
topMargin: 20
|
|
||||||
}
|
|
||||||
enabled: root.mode === "http" ? true : false
|
|
||||||
width: Math.max(parent.width / 2, parent.width - http_url_label.width - anchors.leftMargin)
|
|
||||||
color: root.accent_color
|
|
||||||
font.pointSize: root.font_normal_text_size
|
|
||||||
cursorPosition: 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -414,9 +259,7 @@ Window {
|
||||||
visible: settings_error_text === "" ? false : true
|
visible: settings_error_text === "" ? false : true
|
||||||
anchors {
|
anchors {
|
||||||
topMargin: 20
|
topMargin: 20
|
||||||
top: http_url_label.bottom
|
top: alert_thres_label.bottom
|
||||||
bottom: reset_averages.top
|
|
||||||
bottomMargin: 10
|
|
||||||
left: parent.left
|
left: parent.left
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
@ -425,52 +268,7 @@ Window {
|
||||||
font.pixelSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: reset_averages
|
|
||||||
anchors {
|
|
||||||
topMargin: 10
|
|
||||||
bottom: save_config.top
|
|
||||||
bottomMargin: 10
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
color: "#F0121212"
|
|
||||||
width: parent.width / 1.3
|
|
||||||
height: 60
|
|
||||||
border {
|
|
||||||
width: 1
|
|
||||||
color: root.accent_color
|
|
||||||
}
|
|
||||||
radius: 3
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "Reset Averages"
|
|
||||||
color: root.accent_color
|
|
||||||
font.pointSize: root.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 = reset_averages.color
|
|
||||||
reset_averages.color = "#5A1F1F1F"
|
|
||||||
}
|
|
||||||
onExited: {
|
|
||||||
reset_averages.color = settings_rect_entered_prev
|
|
||||||
}
|
|
||||||
onPressed: {
|
|
||||||
settings_rect_pressed_prev = reset_averages.color
|
|
||||||
reset_averages.color = "#5A1F4F1F"
|
|
||||||
listener.resetAverages();
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
reset_averages.color = settings_rect_pressed_prev
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: save_config
|
id: save_config
|
||||||
|
|
@ -480,7 +278,7 @@ Window {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
color: "#F0121212"
|
color: "#F0121212"
|
||||||
width: parent.width / 1.3
|
width: parent.width / 2.5
|
||||||
height: 60
|
height: 60
|
||||||
border {
|
border {
|
||||||
width: 1
|
width: 1
|
||||||
|
|
@ -512,10 +310,7 @@ Window {
|
||||||
let max = parseFloat(min_thres_input.text);
|
let max = parseFloat(min_thres_input.text);
|
||||||
let min = parseFloat(min_thres_input.text);
|
let min = parseFloat(min_thres_input.text);
|
||||||
let alert = parseFloat(alert_thres_input.text);
|
let alert = parseFloat(alert_thres_input.text);
|
||||||
let flipBits = flip_bits_box.checked;
|
console.log("Parsed values:", max, min, alert);
|
||||||
let mode = root.mode;
|
|
||||||
let url = http_url_input.text;
|
|
||||||
console.log("Parsed values:", max, min, alert, flip_bits_box.checked);
|
|
||||||
if(max < min) {
|
if(max < min) {
|
||||||
settings_error_label.settings_error_text = "Max cannot be less than min";
|
settings_error_label.settings_error_text = "Max cannot be less than min";
|
||||||
return;
|
return;
|
||||||
|
|
@ -524,19 +319,20 @@ Window {
|
||||||
settings_error_label.settings_error_text = "Alert must be between 0 to 100";
|
settings_error_label.settings_error_text = "Alert must be between 0 to 100";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
let alert_effective_reading = (effective_max_reading * (100 - alert) / 100) + current_min_reading;
|
let alert_effective_reading = (effective_max_reading * (100 - alert) / 100) + current_min_reading;
|
||||||
console.log("Alert effective reading is: " + alert_effective_reading + " for value: " + alert);
|
console.log("Alert effective reading is: " + alert_effective_reading + " for value: " + alert);
|
||||||
listener.setConfig(alert_effective_reading, flipBits, mode, url);
|
listener.setAlert(alert_effective_reading);
|
||||||
config.saveConfig(max_thres_input.text, min_thres_input.text, alert_thres_input.text, flip_bits_box.checked, mode, url);
|
config.saveConfig(max_thres_input.text, min_thres_input.text, alert_thres_input.text);
|
||||||
settings_popup.close();
|
settings_popup.close();
|
||||||
}
|
}
|
||||||
onReleased: {
|
onReleased: {
|
||||||
save_config.color = settings_rect_pressed_prev
|
save_config.color = settings_rect_pressed_prev
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -558,7 +354,7 @@ Window {
|
||||||
id: tank_base
|
id: tank_base
|
||||||
color: "#0FFFFFFF"
|
color: "#0FFFFFFF"
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: parent.width / 2
|
width: parent.width / 2.5
|
||||||
height: parent.height / 2
|
height: parent.height / 2
|
||||||
border.color: "#F0121212"
|
border.color: "#F0121212"
|
||||||
border.width: 5
|
border.width: 5
|
||||||
|
|
@ -614,20 +410,6 @@ Window {
|
||||||
color: root.accent_color
|
color: root.accent_color
|
||||||
font.pixelSize: root.font_normal_text_size
|
font.pixelSize: root.font_normal_text_size
|
||||||
}
|
}
|
||||||
Text {
|
|
||||||
id: last_updated_text
|
|
||||||
property string last_updated: ""
|
|
||||||
text: "Last Updated On Server On: " + last_updated
|
|
||||||
anchors {
|
|
||||||
top: info_percent_text.bottom
|
|
||||||
topMargin: 10
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
color: root.accent_color
|
|
||||||
font.pixelSize: root.font_normal_text_size
|
|
||||||
visible: config.mode === "http" ? true : false
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: error_text
|
id: error_text
|
||||||
|
|
@ -635,7 +417,7 @@ Window {
|
||||||
text: "Error: " + error_string
|
text: "Error: " + error_string
|
||||||
visible: error_string === "" ? false : true;
|
visible: error_string === "" ? false : true;
|
||||||
anchors {
|
anchors {
|
||||||
top: last_updated_text.bottom
|
top: info_percent_text.bottom
|
||||||
topMargin: 10
|
topMargin: 10
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
@ -662,40 +444,11 @@ Window {
|
||||||
|
|
||||||
ConfigInterface {
|
ConfigInterface {
|
||||||
id: config
|
id: config
|
||||||
onConfigData: (max, min, alert, mode, url) => {
|
onConfigData: (max, min, alert) => {
|
||||||
console.log("Got config data as: ", max, min, alert, mode, url);
|
console.log("Got config data as: ", max, min, alert);
|
||||||
}
|
|
||||||
onModeChanged: {
|
|
||||||
root.mode = mode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Timer {
|
|
||||||
property int count: 0
|
|
||||||
id: init_timer
|
|
||||||
running: true
|
|
||||||
repeat: true
|
|
||||||
interval: 1000
|
|
||||||
onTriggered: {
|
|
||||||
if(count === 0) {
|
|
||||||
listener.startService();
|
|
||||||
count++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
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 effective_max_reading = Math.max(0, (parseFloat(max_thres_input.text)) - current_min_reading);
|
|
||||||
let alert = parseFloat(alert_thres_input.text);
|
|
||||||
let alert_effective_reading = (effective_max_reading * (100 - alert) / 100) + current_min_reading;
|
|
||||||
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);
|
|
||||||
http_url_input.cursorPosition = 0;
|
|
||||||
init_timer.repeat = false;
|
|
||||||
init_timer.stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPListener {
|
UDPListener {
|
||||||
id: listener
|
id: listener
|
||||||
|
|
@ -704,29 +457,12 @@ Window {
|
||||||
error_text.error_string = err;
|
error_text.error_string = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
onLastUpdatedChanged: (update, warn) => {
|
|
||||||
console.log("QML Last Updated: ", update);
|
|
||||||
if(!warn)
|
|
||||||
{
|
|
||||||
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: {
|
||||||
console.log("Distance changed");
|
console.log("Distance changed");
|
||||||
root.distance = listener.distance;
|
root.distance = listener.distance;
|
||||||
error_text.error_string = "";
|
error_text.error_string = "";
|
||||||
console.log("Distance count: ", root.distance_count);
|
console.log("Distance count: ", root.distance_count);
|
||||||
if(root.distance_count >= root.distance_count_thres) {
|
if(root.distance_count >= 5) {
|
||||||
if(loading_popup.opened) {
|
|
||||||
loading_popup.close();
|
|
||||||
}
|
|
||||||
status_label.text = "Recieving values";
|
status_label.text = "Recieving values";
|
||||||
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);
|
||||||
|
|
@ -742,9 +478,7 @@ Window {
|
||||||
else {
|
else {
|
||||||
water_level.color = root.water_color;
|
water_level.color = root.water_color;
|
||||||
}
|
}
|
||||||
if(root.distance_count > 1000) {
|
|
||||||
root.distance_count = root.distance_count_thres;
|
|
||||||
}
|
|
||||||
console.log("Current reading is: " + current_reading)
|
console.log("Current reading is: " + current_reading)
|
||||||
console.log("Normalized height is: " + normalized_height)
|
console.log("Normalized height is: " + normalized_height)
|
||||||
water_level.current_level = normalized_height;
|
water_level.current_level = normalized_height;
|
||||||
|
|
@ -773,29 +507,23 @@ Window {
|
||||||
let alert = parseFloat(alert_thres_input.text);
|
let alert = parseFloat(alert_thres_input.text);
|
||||||
let alert_effective_reading = (effective_max_reading * (100 - alert) / 100) + current_min_reading;
|
let alert_effective_reading = (effective_max_reading * (100 - alert) / 100) + current_min_reading;
|
||||||
console.log("Alert effective reading is: " + alert_effective_reading + " for value: " + alert);
|
console.log("Alert effective reading is: " + alert_effective_reading + " for value: " + alert);
|
||||||
listener.setConfig(alert_effective_reading, flip_bits_box.checked, root.mode, http_url_input.text);
|
listener.setAlert(alert_effective_reading);
|
||||||
}
|
}
|
||||||
|
|
||||||
distance_count += 1;
|
distance_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataBlink() {
|
function dataBlink() {
|
||||||
if(status_indicator_timer.running) {
|
let old_color = status_indicator.color;
|
||||||
status_indicator_timer.stop();
|
|
||||||
}
|
|
||||||
let old_color = "#F05F5F0F";
|
|
||||||
let new_color = "#F04FAF5F";
|
let new_color = "#F04FAF5F";
|
||||||
status_indicator.color = new_color;
|
status_indicator.color = new_color;
|
||||||
status_indicator.old_color = old_color;
|
status_indicator.old_color = old_color;
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,3 @@ On Android Creates a service from service.cpp and android/src/org/qtproject/exam
|
||||||
Changes in AndroidManifest.xml are important.<br>
|
Changes in AndroidManifest.xml are important.<br>
|
||||||
On Desktop just waits for values from a UDP Broadcast on local network with port 8176 and shows those values.<br>
|
On Desktop just waits for values from a UDP Broadcast on local network with port 8176 and shows those values.<br>
|
||||||
On Android the service does that, and creates an alert notification if the value in broadcast is less than alert threshold.<br>
|
On Android the service does that, and creates an alert notification if the value in broadcast is less than alert threshold.<br>
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
Create a new socket in Worker that will instantly start listening.<br>
|
|
||||||
In the service launch the threads and immediately send client hello to the worker socket.<br>
|
|
||||||
On client hello send command data to the android service.<br>
|
|
||||||
On quit send server bye to android service.<br>
|
|
||||||
On server bye deinit the sockets that send data to cpp server.<br>
|
|
||||||
On next launch, the command and client threads can be reinitialized from the StartService java class.<br>
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" />
|
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" />
|
||||||
<supports-screens
|
<supports-screens
|
||||||
|
|
@ -28,12 +28,10 @@
|
||||||
android:fullBackupOnly="false">
|
android:fullBackupOnly="false">
|
||||||
|
|
||||||
<service android:name=".WaterLevelService"
|
<service android:name=".WaterLevelService"
|
||||||
android:foregroundServiceType="connectedDevice"
|
android:foregroundServiceType="specialUse"
|
||||||
android:exported="true"
|
android:exported="true">
|
||||||
android:process=":water_service"
|
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||||
android:stopWithTask="false">
|
android:value="Monitoring water levels via local network UDP packets for real-time sensor alerts." />
|
||||||
<!-- <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." />-->
|
|
||||||
<meta-data android:name="android.app.lib_name" android:value="service"/>
|
<meta-data android:name="android.app.lib_name" android:value="service"/>
|
||||||
<meta-data android:name="android.app.background_running" android:value="true"/>
|
<meta-data android:name="android.app.background_running" android:value="true"/>
|
||||||
</service>
|
</service>
|
||||||
|
|
|
||||||
|
|
@ -19,190 +19,39 @@ import org.qtproject.qt.android.bindings.QtActivity;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
|
|
||||||
public class WaterLevelService extends Service {
|
public class WaterLevelService extends Service {
|
||||||
|
|
||||||
private static float alert_thres_distance = 1000000;
|
private static float alert_thres_distance = 1000000;
|
||||||
private static boolean bits_flipped = false;
|
|
||||||
private static String mode = "";
|
|
||||||
private static String url = "";
|
|
||||||
private static Thread udpThread;
|
|
||||||
private static Thread cmdThread;
|
|
||||||
private static boolean resetBinds = false;
|
|
||||||
private final IBinder binder = new LocalBinder();
|
|
||||||
final Messenger mMessenger = new Messenger(new IncomingHandler());
|
|
||||||
public static final int MSG_RESTART_THREADS = 1;
|
|
||||||
|
|
||||||
|
|
||||||
class IncomingHandler extends Handler {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
switch (msg.what) {
|
|
||||||
case MSG_RESTART_THREADS:
|
|
||||||
Log.d("UDP Service MainThread", "Received IPC request to restart threads");
|
|
||||||
restartThreads();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
super.handleMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized void restartThreads() {
|
|
||||||
Log.d("UDP Service MainThread", "In synchronized thread stopper.");
|
|
||||||
udpThread.interrupt();
|
|
||||||
cmdThread.interrupt();
|
|
||||||
try {
|
|
||||||
udpThread.join();
|
|
||||||
cmdThread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.d("UDP Service MainThread", "Thread joining was interrupted because of: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 MainThread", "Restarting the threads", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
Log.d("UDP Service MainThread", "Actually restarting the thread");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized boolean checkBound() {
|
|
||||||
return resetBinds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void setBound(boolean value) {
|
|
||||||
resetBinds = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LocalBinder extends android.os.Binder {
|
|
||||||
WaterLevelService getService() {
|
|
||||||
return WaterLevelService.this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 CommandThread", "Command thread initialising");
|
Log.d("UDP Service", "Command thread initialising");
|
||||||
try {
|
try {
|
||||||
socket_cmd_recv = new DatagramSocket(null);
|
socket_cmd_recv = new DatagramSocket(8178, InetAddress.getByName("localhost"));
|
||||||
socket_cmd_send = new DatagramSocket(null);
|
socket_cmd_send = new DatagramSocket(8179);
|
||||||
socket_cmd_recv.setSoTimeout(4000);
|
|
||||||
socket_cmd_recv.setReuseAddress(true);
|
Log.d("UDP Service", "Created command thread sockets");
|
||||||
socket_cmd_send.setReuseAddress(true);
|
|
||||||
socket_cmd_recv.bind(new InetSocketAddress(8178));
|
|
||||||
socket_cmd_send.bind(new InetSocketAddress(8187));
|
|
||||||
boolean not_send_set = true;
|
|
||||||
Log.d("UDP Service CommandThread", "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(8187));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(not_send_set) {
|
|
||||||
String s_data = new String("<SET>");
|
|
||||||
byte[] buff_s = s_data.getBytes(StandardCharsets.UTF_8);
|
|
||||||
DatagramPacket packet = new DatagramPacket(buff_s, buff_s.length, InetAddress.getByName("127.0.0.1"), 8186);
|
|
||||||
try {
|
|
||||||
socket_cmd_send.connect(InetAddress.getByName("127.0.0.1"), 8186);
|
|
||||||
socket_cmd_send.send(packet);
|
|
||||||
} catch(Exception e) {
|
|
||||||
Log.d("UDP Service CommandThread", "Failed to send data to client due to: " + e);
|
|
||||||
}
|
|
||||||
Log.d("UDP Service CommandThread", "Sent set message to client");
|
|
||||||
}
|
|
||||||
|
|
||||||
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 CommandThread", "Received command packet " + str);
|
|
||||||
not_send_set = false;
|
|
||||||
if(str.startsWith("<SET NAME=ALERT VALUE=")) {
|
if(str.startsWith("<SET NAME=ALERT VALUE=")) {
|
||||||
str = str.replace("<SET NAME=ALERT VALUE=", "");
|
str = str.replace("<SET NAME=ALERT VALUE=", "");
|
||||||
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 CommandThread", "Set Bound to True");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log.d("UDP Service CommandThread", "Set Bound is False");
|
|
||||||
}
|
}
|
||||||
|
Log.d("UDP Service ", "Received command packet " + str);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(str.startsWith("<SET NAME=BITS_FLIPPED VALUE=")) {
|
|
||||||
str = str.replace("<SET NAME=BITS_FLIPPED VALUE=", "");
|
|
||||||
str = str.replace("=", "");
|
|
||||||
str = str.replace(">", "");
|
|
||||||
Log.d("UDP Service CommandThread", "Flipping " + str);
|
|
||||||
if(str.toLowerCase() == "false") {
|
|
||||||
bits_flipped = false;
|
|
||||||
}
|
|
||||||
else if(str.toLowerCase() == "true") {
|
|
||||||
bits_flipped = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(str.startsWith("<SET NAME=MODE VALUE=")) {
|
|
||||||
str = str.replace("<SET NAME=MODE VALUE=", "");
|
|
||||||
str = str.replace("=", "");
|
|
||||||
str = str.replace(">", "");
|
|
||||||
Log.d("UDP Service CommandThread", "Mode " + str);
|
|
||||||
mode = str.toLowerCase();
|
|
||||||
}
|
|
||||||
else if(str.startsWith("<SET NAME=URL VALUE=")) {
|
|
||||||
str = str.replace("<SET NAME=URL VALUE=", "");
|
|
||||||
str = str.replace("=", "");
|
|
||||||
str = str.replace(">", "");
|
|
||||||
Log.d("UDP Service CommandThread", "Url " + str);
|
|
||||||
url = str.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// showToast("IOException: " + e);
|
Log.e("UDP Service", "Socket Error", e);
|
||||||
Log.e("UDP Service CommandThread", "IOException Error" + e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,15 +61,13 @@ public class WaterLevelService extends Service {
|
||||||
private DatagramSocket socket_recv;
|
private DatagramSocket socket_recv;
|
||||||
private DatagramSocket socket_send;
|
private DatagramSocket socket_send;
|
||||||
private Instant prevAlertTimestamp;
|
private Instant prevAlertTimestamp;
|
||||||
private InetAddress address;
|
|
||||||
private boolean started = false;
|
private boolean started = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.d("UDP Service ClientThread", "Client Thread initialising");
|
Log.d("UDP Service", "Thread initialising");
|
||||||
android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) getSystemService(Context.WIFI_SERVICE);
|
android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) getSystemService(Context.WIFI_SERVICE);
|
||||||
android.net.wifi.WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("water_level_lock");
|
android.net.wifi.WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("water_level_lock");
|
||||||
android.net.wifi.WifiManager.WifiLock wifiLock = wifi.createWifiLock(android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF, "WaterLevel:WifiLock");
|
|
||||||
android.os.PowerManager pm = (android.os.PowerManager) getSystemService(Context.POWER_SERVICE);
|
android.os.PowerManager pm = (android.os.PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||||
android.os.PowerManager.WakeLock wakeLock = pm.newWakeLock(android.os.PowerManager.PARTIAL_WAKE_LOCK, "WaterLevel:WakeLock");
|
android.os.PowerManager.WakeLock wakeLock = pm.newWakeLock(android.os.PowerManager.PARTIAL_WAKE_LOCK, "WaterLevel:WakeLock");
|
||||||
|
|
||||||
|
|
@ -237,144 +84,17 @@ public class WaterLevelService extends Service {
|
||||||
try {
|
try {
|
||||||
multicastLock.acquire();
|
multicastLock.acquire();
|
||||||
wakeLock.acquire();
|
wakeLock.acquire();
|
||||||
wifiLock.acquire();
|
socket_recv = new DatagramSocket(8176);
|
||||||
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);
|
Log.d("UDP Service", "Created Sockets");
|
||||||
socket_recv.setReuseAddress(true);
|
|
||||||
socket_send.setReuseAddress(true);
|
|
||||||
socket_send.bind(new InetSocketAddress(8177));
|
|
||||||
socket_recv.bind(new InetSocketAddress(8176));
|
|
||||||
Log.d("UDP Service ClientThread", "Created Sockets");
|
|
||||||
int count = 0;
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
count++;
|
byte[] buffer = new byte[4];
|
||||||
if(count == 3) {
|
|
||||||
Log.i("UDP Service ClientThread", "Thread is running with mode: " + mode);
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
if(checkBound()) {
|
|
||||||
Log.i("UDP Service ClientThread", "Reconnecting sockets");
|
|
||||||
this.address = InetAddress.getByName("127.0.0.1");
|
|
||||||
socket_recv.disconnect();
|
|
||||||
socket_send.disconnect();
|
|
||||||
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 ClientThread", "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;
|
|
||||||
String updated = "";
|
|
||||||
if(mode.equals("udp")) {
|
|
||||||
try {
|
|
||||||
if(socket_recv.isClosed()) {
|
|
||||||
socket_recv.bind(new InetSocketAddress(8176));
|
|
||||||
}
|
|
||||||
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);
|
||||||
} catch(java.net.SocketTimeoutException e) {
|
float f = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getFloat();
|
||||||
// showToast("Socket Timeout: " + e);
|
Log.d("UDP Service ", "Received packet: " + f);
|
||||||
continue;
|
Log.d("UDP Service ", "Threshold is: " + alert_thres_distance);
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(mode.equals("http")) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(2000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.d("UDP Service ClientThread", "Thread exiting due to interrupt.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Log.d("UDP Service ClientThread", "Http String Url: " + url);
|
|
||||||
URL t_url = new URL(url);
|
|
||||||
HttpURLConnection con = (HttpURLConnection) t_url.openConnection();
|
|
||||||
con.setRequestMethod("GET");
|
|
||||||
con.setConnectTimeout(5000);
|
|
||||||
con.setReadTimeout(5000);
|
|
||||||
con.setInstanceFollowRedirects(true);
|
|
||||||
int status = con.getResponseCode();
|
|
||||||
Log.d("UDP Service ClientThread", "Got status from http: " + status);
|
|
||||||
if(status == 200) {
|
|
||||||
BufferedReader streamReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
|
||||||
String data = streamReader.readLine();
|
|
||||||
try {
|
|
||||||
JSONObject obj = new JSONObject(data);
|
|
||||||
JSONArray arr = obj.getJSONArray("water_level");
|
|
||||||
float f = (float ) arr.getDouble(0);
|
|
||||||
updated = obj.getString("updated_on");
|
|
||||||
buffer = ByteBuffer.allocate(4).putFloat(f).array();
|
|
||||||
Log.d("UDP Service ClientThread", "Got value from http: " + f);
|
|
||||||
Log.d("UDP Service ClientThread", "Last updated on: " + updated);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
Log.e("UDP Service ClientThread", "Invalid Json");
|
|
||||||
// showToast("Invalid Json" + e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// showToast("Bad Response From Server: " + status);
|
|
||||||
InputStreamReader streamReader = new InputStreamReader(con.getErrorStream());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log.d("UDP Service ClientThread", "Invalid mode: " + mode);
|
|
||||||
// showToast("Invalid mode: " + mode);
|
|
||||||
try {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.d("UDP Service ClientThread", "Thread exiting due to interrupt.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
float f;
|
|
||||||
if(bits_flipped) {
|
|
||||||
f = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getFloat();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
f = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN).getFloat();
|
|
||||||
}
|
|
||||||
Log.d("UDP Service ClientThread", "Received packet: " + f);
|
|
||||||
Log.d("UDP Service ClientThread", "Threshold is: " + alert_thres_distance);
|
|
||||||
boolean duration_passed = false;
|
boolean duration_passed = false;
|
||||||
if(!started) {
|
if(!started) {
|
||||||
duration_passed = true;
|
duration_passed = true;
|
||||||
|
|
@ -383,7 +103,7 @@ public class WaterLevelService extends Service {
|
||||||
else {
|
else {
|
||||||
Instant currentTimestamp = Instant.now();
|
Instant currentTimestamp = Instant.now();
|
||||||
Duration duration = Duration.between(prevAlertTimestamp, currentTimestamp);
|
Duration duration = Duration.between(prevAlertTimestamp, currentTimestamp);
|
||||||
if(duration.toMinutes() > 60) {
|
if(duration.toMinutes() > 30) {
|
||||||
duration_passed = true;
|
duration_passed = true;
|
||||||
}
|
}
|
||||||
prevAlertTimestamp = currentTimestamp;
|
prevAlertTimestamp = currentTimestamp;
|
||||||
|
|
@ -393,33 +113,18 @@ public class WaterLevelService extends Service {
|
||||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||||
.setContentTitle("Water Level Sensor")
|
.setContentTitle("Water Level Sensor")
|
||||||
.setContentText("Water Level is below alert threshold")
|
.setContentText("Water Level is below alert threshold")
|
||||||
.setPriority(Notification.PRIORITY_LOW);
|
.setPriority(Notification.PRIORITY_HIGH);
|
||||||
manager.notify(2, builder.build());
|
manager.notify(2, builder.build());
|
||||||
Log.d("UDP Service ClientThread", "Notification sent");
|
Log.d("UDP Service", "Notification sent");
|
||||||
if(!started) {
|
|
||||||
started = true;
|
|
||||||
}
|
}
|
||||||
}
|
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 8180);
|
||||||
if(socket_send.isClosed()) {
|
|
||||||
socket_send.bind(new InetSocketAddress(8177));
|
|
||||||
}
|
|
||||||
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("127.0.0.1"), 8180);
|
|
||||||
socket_send.send(send_packet);
|
socket_send.send(send_packet);
|
||||||
Log.d("UDP Service ClientThread", "Sent packet");
|
Log.d("UDP Service ", "Sent packet");
|
||||||
if(mode.equals("http")) {
|
|
||||||
byte[] buff2 = updated.getBytes(StandardCharsets.UTF_8);
|
|
||||||
DatagramPacket send_packet_2 = new DatagramPacket(buff2, buff2.length, InetAddress.getByName("127.0.0.1"), 8185);
|
|
||||||
socket_send.send(send_packet_2);
|
|
||||||
Log.d("UDP Service ClientThread", "Sent last updated packet");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// showToast("IOException: " + e);
|
Log.e("UDP Service", "Socket Error", e);
|
||||||
Log.e("UDP Service ClientThread", "IOException Error" + e);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (wifiLock.isHeld())
|
|
||||||
wifiLock.release();
|
|
||||||
if (multicastLock.isHeld())
|
if (multicastLock.isHeld())
|
||||||
multicastLock.release();
|
multicastLock.release();
|
||||||
if (wakeLock.isHeld())
|
if (wakeLock.isHeld())
|
||||||
|
|
@ -431,7 +136,7 @@ public class WaterLevelService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startWaterLevelService() {
|
public void startWaterLevelService() {
|
||||||
Log.d("UDP Service MainThread", "Starting the service from Activity");
|
Log.d("UDP Service", "Starting the service from Activity");
|
||||||
|
|
||||||
Intent intent = new Intent(this, WaterLevelService.class);
|
Intent intent = new Intent(this, WaterLevelService.class);
|
||||||
|
|
||||||
|
|
@ -439,25 +144,25 @@ public class WaterLevelService extends Service {
|
||||||
}
|
}
|
||||||
public WaterLevelService() {
|
public WaterLevelService() {
|
||||||
super();
|
super();
|
||||||
Log.i("UDP Service MainThread", "Class is created");
|
Log.i("UDP Service", "Class is created");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public android.os.IBinder onBind(android.content.Intent intent) { return mMessenger.getBinder(); }
|
public android.os.IBinder onBind(android.content.Intent intent) { return null; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
Notification notification = createNotification();
|
Notification notification = createNotification();
|
||||||
startForeground(1, notification);
|
startForeground(1, notification);
|
||||||
Log.i("UDP Service MainThread", "Creating Service");
|
Log.i("UDP Service", "Creating Service");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
Log.i("UDP Service MainThread", "Destroying Service");
|
Log.i("UDP Service", "Destroying Service");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -465,47 +170,16 @@ public class WaterLevelService extends Service {
|
||||||
Notification notification = createNotification();
|
Notification notification = createNotification();
|
||||||
startForeground(1, notification);
|
startForeground(1, notification);
|
||||||
|
|
||||||
|
Log.d("UDP Service", "Actually starting the thread");
|
||||||
if (intent == null) {
|
|
||||||
Log.w("UDP Service MainThread", "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 MainThread", "Error starting threads", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
Log.d("UDP Service MainThread", "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_NOT_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showToast(String str) {
|
|
||||||
int duration = Toast.LENGTH_SHORT;
|
|
||||||
Toast toast = Toast.makeText(this, str, duration);
|
|
||||||
toast.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Notification createNotification() {
|
private Notification createNotification() {
|
||||||
String channelId = "water_level_channel";
|
String channelId = "water_level_channel";
|
||||||
|
|
@ -528,7 +202,7 @@ public class WaterLevelService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startQtAndroidService(QtActivity activity) {
|
public static void startQtAndroidService(QtActivity activity) {
|
||||||
Log.d("UDP Service MainThread", "Starting the service");
|
Log.d("UDP Service", "Starting the service");
|
||||||
Intent intent = new Intent(activity, WaterLevelService.class);
|
Intent intent = new Intent(activity, WaterLevelService.class);
|
||||||
activity.startForegroundService(intent);
|
activity.startForegroundService(intent);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,114 +5,15 @@ 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;
|
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
|
|
||||||
public class WaterLevelServiceStarter {
|
public class WaterLevelServiceStarter {
|
||||||
private static Messenger mServiceMessenger = null;
|
|
||||||
private static boolean mBound = false;
|
|
||||||
private static boolean restart_bind = false;
|
|
||||||
|
|
||||||
private static ServiceConnection connection = new ServiceConnection() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
|
||||||
mServiceMessenger = new Messenger(service);
|
|
||||||
mBound = true;
|
|
||||||
Log.d("UDP Service StarterThread", "Connected to Service object reference");
|
|
||||||
if(restart_bind)
|
|
||||||
{
|
|
||||||
sendRestartMessage();
|
|
||||||
Log.d("UDP Service StarterThread", "Restart Threads in Service.");
|
|
||||||
}
|
|
||||||
restart_bind = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceDisconnected(ComponentName arg0) {
|
|
||||||
mServiceMessenger = null;
|
|
||||||
mBound = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static void startAndBindService(Context context) {
|
|
||||||
Intent intent = new Intent(context, WaterLevelService.class);
|
|
||||||
context.startForegroundService(intent);
|
|
||||||
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindService(Context context) {
|
|
||||||
restart_bind = true;
|
|
||||||
Intent intent = new Intent(context, WaterLevelService.class);
|
|
||||||
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 sendRestartMessage() {
|
|
||||||
if (!mBound || mServiceMessenger == null) {
|
|
||||||
Log.d("UDP Service StarterThread", "Service is not running.");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Message msg = Message.obtain(null, WaterLevelService.MSG_RESTART_THREADS);
|
|
||||||
mServiceMessenger.send(msg);
|
|
||||||
Log.d("UDP Service StarterThread", "Sent restart signal to remote process");
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e("UDP Service StarterThread", "Failed to send message", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
// Intent intent = new Intent(context, WaterLevelService.class);
|
|
||||||
// context.startForegroundService(intent);
|
|
||||||
// }
|
|
||||||
|
|
||||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
context.startForegroundService(intent);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
if (!isMyServiceRunning(WaterLevelService.class, context)) {
|
|
||||||
Log.d("UDP Service StarterThread", "Starting service safely on Main Looper");
|
|
||||||
startAndBindService(context);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log.d("UDP Service StarterThread", "Service already running, so restarting the threads.");
|
|
||||||
bindService(context);
|
|
||||||
}
|
|
||||||
Log.d("UDP Service StarterThread", "Background service running with pid: " + getServicePid(WaterLevelService.class, context));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,30 +21,20 @@ ConfigInterface::ConfigInterface(QObject *parent)
|
||||||
auto data = config.readAll();
|
auto data = config.readAll();
|
||||||
config.close();
|
config.close();
|
||||||
QJsonObject top = QJsonDocument::fromJson(data).object();
|
QJsonObject top = QJsonDocument::fromJson(data).object();
|
||||||
QString max, min, alert, mode, url;
|
QString max, min, alert;
|
||||||
bool flipbits;
|
max = top["max_threshold"].toString();
|
||||||
max = top["max_threshold"].toString("110");
|
min = top["min_threshold"].toString();
|
||||||
min = top["min_threshold"].toString("10");
|
alert = top["alert_threshold"].toString();
|
||||||
alert = top["alert_threshold"].toString("30");
|
|
||||||
flipbits = top["flip_bits"].toBool(true);
|
|
||||||
mode = top["mode"].toString("http");
|
|
||||||
url = top["url"].toString("https://unrealdragon.in/server/waterlevel");
|
|
||||||
setMax(max);
|
setMax(max);
|
||||||
setMin(min);
|
setMin(min);
|
||||||
setAlert(alert);
|
setAlert(alert);
|
||||||
setFlipBits(flipbits);
|
|
||||||
setMode(mode);
|
|
||||||
setUrl(url);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qDebug() << "File does not exist creating one...";
|
qDebug() << "File does not exist creating one...";
|
||||||
QJsonObject top;
|
QJsonObject top;
|
||||||
top["max_threshold"] = "110";
|
top["max_threshold"] = "125";
|
||||||
top["min_threshold"] = "10";
|
top["min_threshold"] = "25";
|
||||||
top["alert_threshold"] = "30";
|
top["alert_threshold"] = "100";
|
||||||
top["flip_bits"] = true;
|
|
||||||
top["mode"] = "http";
|
|
||||||
top["url"] = "https://unrealdragon.in/server/waterlevel";
|
|
||||||
QByteArray data = QJsonDocument(top).toJson();
|
QByteArray data = QJsonDocument(top).toJson();
|
||||||
bool ok = config.open(QFile::WriteOnly);
|
bool ok = config.open(QFile::WriteOnly);
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
|
|
@ -54,17 +44,10 @@ ConfigInterface::ConfigInterface(QObject *parent)
|
||||||
config.write(data);
|
config.write(data);
|
||||||
config.flush();
|
config.flush();
|
||||||
config.close();
|
config.close();
|
||||||
setMax("110");
|
|
||||||
setMin("10");
|
|
||||||
setAlert("30");
|
|
||||||
setFlipBits(true);
|
|
||||||
setMode("http");
|
|
||||||
setUrl("https://unrealdragon.in/server/waterlevel");
|
|
||||||
qDebug() << "Config set initial values completed";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigInterface::saveConfig(QString max, QString min, QString alert, bool flipbits, QString mode, QString url)
|
void ConfigInterface::saveConfig(QString max, QString min, QString alert)
|
||||||
{
|
{
|
||||||
auto paths = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
auto paths = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
qDebug() << "Got writable path as: " << paths;
|
qDebug() << "Got writable path as: " << paths;
|
||||||
|
|
@ -75,13 +58,9 @@ void ConfigInterface::saveConfig(QString max, QString min, QString alert, bool f
|
||||||
top["max_threshold"] = max;
|
top["max_threshold"] = max;
|
||||||
top["min_threshold"] = min;
|
top["min_threshold"] = min;
|
||||||
top["alert_threshold"] = alert;
|
top["alert_threshold"] = alert;
|
||||||
top["flip_bits"] = flipbits;
|
|
||||||
top["mode"] = mode;
|
|
||||||
top["url"] = url;
|
|
||||||
setMax(max);
|
setMax(max);
|
||||||
setMin(min);
|
setMin(min);
|
||||||
setAlert(alert);
|
setAlert(alert);
|
||||||
setMode(mode);
|
|
||||||
QByteArray data = QJsonDocument(top).toJson();
|
QByteArray data = QJsonDocument(top).toJson();
|
||||||
config.open(QIODevice::WriteOnly);
|
config.open(QIODevice::WriteOnly);
|
||||||
config.write(data);
|
config.write(data);
|
||||||
|
|
@ -127,42 +106,3 @@ void ConfigInterface::setMin(const QString &newMin)
|
||||||
m_min = newMin;
|
m_min = newMin;
|
||||||
emit minChanged();
|
emit minChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigInterface::flipBits() const
|
|
||||||
{
|
|
||||||
return m_flipBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigInterface::setFlipBits(bool newFlipBits)
|
|
||||||
{
|
|
||||||
if (m_flipBits == newFlipBits)
|
|
||||||
return;
|
|
||||||
m_flipBits = newFlipBits;
|
|
||||||
emit flipBitsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ConfigInterface::mode() const
|
|
||||||
{
|
|
||||||
return m_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigInterface::setMode(const QString &newMode)
|
|
||||||
{
|
|
||||||
if (m_mode == newMode)
|
|
||||||
return;
|
|
||||||
m_mode = newMode;
|
|
||||||
emit modeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ConfigInterface::url() const
|
|
||||||
{
|
|
||||||
return m_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigInterface::setUrl(const QString &newUrl)
|
|
||||||
{
|
|
||||||
if (m_url == newUrl)
|
|
||||||
return;
|
|
||||||
m_url = newUrl;
|
|
||||||
emit urlChanged();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,6 @@ class ConfigInterface : public QObject
|
||||||
Q_PROPERTY(QString min READ min WRITE setMin NOTIFY minChanged FINAL)
|
Q_PROPERTY(QString min READ min WRITE setMin NOTIFY minChanged FINAL)
|
||||||
Q_PROPERTY(QString max READ max WRITE setMax NOTIFY maxChanged FINAL)
|
Q_PROPERTY(QString max READ max WRITE setMax NOTIFY maxChanged FINAL)
|
||||||
Q_PROPERTY(QString alert READ alert WRITE setAlert NOTIFY alertChanged FINAL)
|
Q_PROPERTY(QString alert READ alert WRITE setAlert NOTIFY alertChanged FINAL)
|
||||||
Q_PROPERTY(QString mode READ mode WRITE setMode NOTIFY modeChanged FINAL)
|
|
||||||
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged FINAL)
|
|
||||||
Q_PROPERTY(bool flipBits READ flipBits WRITE setFlipBits NOTIFY flipBitsChanged FINAL)
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigInterface(QObject *parent = nullptr);
|
explicit ConfigInterface(QObject *parent = nullptr);
|
||||||
QString alert() const;
|
QString alert() const;
|
||||||
|
|
@ -31,33 +28,18 @@ public:
|
||||||
QString min() const;
|
QString min() const;
|
||||||
void setMin(const QString &newMin);
|
void setMin(const QString &newMin);
|
||||||
|
|
||||||
bool flipBits() const;
|
|
||||||
void setFlipBits(bool newFlipBits);
|
|
||||||
|
|
||||||
QString mode() const;
|
|
||||||
void setMode(const QString &newMode);
|
|
||||||
|
|
||||||
QString url() const;
|
|
||||||
void setUrl(const QString &newUrl);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void configData(QString max, QString min, QString alert, bool flipbits, QString mode, QString url);
|
void configData(QString max, QString min, QString alert);
|
||||||
void alertChanged();
|
void alertChanged();
|
||||||
void maxChanged();
|
void maxChanged();
|
||||||
void minChanged();
|
void minChanged();
|
||||||
void flipBitsChanged();
|
|
||||||
void modeChanged();
|
|
||||||
void urlChanged();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void saveConfig(QString max, QString min, QString alert, bool flipbits, QString mode, QString url);
|
void saveConfig(QString max, QString min, QString alert);
|
||||||
private:
|
private:
|
||||||
QString m_alert;
|
QString m_alert;
|
||||||
QString m_max;
|
QString m_max;
|
||||||
QString m_min;
|
QString m_min;
|
||||||
bool m_flipBits;
|
|
||||||
QString m_mode;
|
|
||||||
QString m_url;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONFIGINTERFACE_H
|
#endif // CONFIGINTERFACE_H
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef MOVING_CONTAINER
|
#ifndef MOVING_CONTAINER
|
||||||
#define MOVING_CONTAINER
|
#define MOVING_CONTAINER
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
using ld = long double;
|
using ld = long double;
|
||||||
|
|
||||||
template<typename T> class average {
|
template<typename T> class average {
|
||||||
|
|
@ -21,16 +21,11 @@ public:
|
||||||
|
|
||||||
~average() {
|
~average() {
|
||||||
curr = head;
|
curr = head;
|
||||||
if(!curr)
|
|
||||||
return;
|
|
||||||
while(curr != nullptr) {
|
while(curr != nullptr) {
|
||||||
info *now = curr;
|
info *now = curr;
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
delete now;
|
delete now;
|
||||||
}
|
}
|
||||||
curr = nullptr;
|
|
||||||
head = nullptr;
|
|
||||||
tail = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int size() {
|
unsigned int size() {
|
||||||
|
|
@ -41,21 +36,6 @@ public:
|
||||||
return this->avg;
|
return this->avg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
|
||||||
curr = head;
|
|
||||||
if(!curr)
|
|
||||||
return;
|
|
||||||
while(curr != nullptr) {
|
|
||||||
info *now = curr;
|
|
||||||
curr = curr->next;
|
|
||||||
delete now;
|
|
||||||
}
|
|
||||||
curr = nullptr;
|
|
||||||
head = nullptr;
|
|
||||||
tail = nullptr;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void recalculate_average() {
|
void recalculate_average() {
|
||||||
curr = head;
|
curr = head;
|
||||||
this->avg = 0;
|
this->avg = 0;
|
||||||
|
|
|
||||||
143
service.cpp
143
service.cpp
|
|
@ -11,6 +11,7 @@
|
||||||
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) {
|
||||||
|
|
@ -28,95 +29,87 @@ 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;
|
|
||||||
|
|
||||||
// // if(!nativesRegistered) {
|
using namespace QtJniTypes;
|
||||||
// // // jclass javaClass = env.findClass("org/qtproject/example/appwaterLevelSensor/WaterLevelReceiver");
|
using namespace QNativeInterface;
|
||||||
// // // 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();
|
|
||||||
// auto serviceClass = env.findClass(Traits<WaterLevelService>::className());
|
|
||||||
// if (!serviceClass) {
|
|
||||||
// qDebug() << "FAILED to find WaterLevelService class!";
|
|
||||||
// env->ExceptionDescribe(); // VERY important
|
|
||||||
// env->ExceptionClear();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (context.isValid()) {
|
|
||||||
// QJniObject::callStaticMethod<
|
|
||||||
// void>(
|
|
||||||
// "org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter",
|
|
||||||
// "startService",
|
|
||||||
// "(Landroid/content/Context;)V",
|
|
||||||
// context.object<jobject>());
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void service::moveAppToBackground()
|
|
||||||
{
|
|
||||||
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 context = QNativeInterface::QAndroidApplication::context();
|
||||||
|
|
||||||
|
QJniEnvironment env;
|
||||||
|
auto serviceClass = env.findClass(Traits<WaterLevelService>::className());
|
||||||
|
if (!serviceClass) {
|
||||||
|
qDebug() << "FAILED to find WaterLevelService class!";
|
||||||
|
env->ExceptionDescribe(); // VERY important
|
||||||
|
env->ExceptionClear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass javaClass = env.findClass("org/qtproject/example/appwaterLevelSensor/WaterLevelReceiver");
|
||||||
|
env->RegisterNatives(javaClass, methods, 1);
|
||||||
|
|
||||||
|
|
||||||
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>()
|
context.object<jobject>()); // pass the QtActivity instance );
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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,8 +8,6 @@ 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:
|
||||||
};
|
};
|
||||||
|
|
|
||||||
382
udplistener.cpp
382
udplistener.cpp
|
|
@ -1,19 +1,19 @@
|
||||||
#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();
|
worker = new Worker(this);
|
||||||
thread = new QThread();
|
thread = new QThread(this);
|
||||||
worker->moveToThread(thread);
|
worker->moveToThread(thread);
|
||||||
connect(worker, &Worker::lastUpdateddatagramReceived, this, &UDPListener::lastUpdateddatagramReceived);
|
|
||||||
connect(worker, &Worker::datagramReceived, this, &UDPListener::datagramRecieved);
|
connect(worker, &Worker::datagramReceived, this, &UDPListener::datagramRecieved);
|
||||||
connect(worker, &Worker::socketError, this, &UDPListener::socketError);
|
connect(worker, &Worker::socketError, this, &UDPListener::socketError);
|
||||||
connect(worker, &Worker::sendConfig, this, &UDPListener::sendConfigOnSet);
|
|
||||||
connect(this, &UDPListener::startWorker, worker, &Worker::run);
|
connect(this, &UDPListener::startWorker, worker, &Worker::run);
|
||||||
connect(this, &UDPListener::changeWorkerMode, worker, &Worker::changeMode);
|
|
||||||
thread->start();
|
thread->start();
|
||||||
emit startWorker();
|
emit startWorker();
|
||||||
timer = new QTimer(this);
|
timer = new QTimer(this);
|
||||||
|
|
@ -21,6 +21,11 @@ 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
|
||||||
|
|
@ -34,118 +39,26 @@ void UDPListener::setDistance(double newDistance)
|
||||||
emit distanceChanged();
|
emit distanceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPListener::sendConfigOnSet()
|
void UDPListener::setAlert(float distance)
|
||||||
{
|
{
|
||||||
bool flip_bits = m_flip_bits;
|
|
||||||
QString url = m_url;
|
|
||||||
QString mode = m_mode;
|
|
||||||
float distance = m_distance;
|
|
||||||
if(!command_socket) {
|
if(!command_socket) {
|
||||||
command_socket = new QUdpSocket(this);
|
command_socket = new QUdpSocket(this);
|
||||||
bool bind = command_socket->bind(QHostAddress::Any, 0);
|
bool bind = command_socket->bind(8181);
|
||||||
if(bind) {
|
if(bind) {
|
||||||
QNetworkDatagram data1, data2, data3, data4;
|
QNetworkDatagram data;
|
||||||
data1.setDestination(QHostAddress::LocalHost, 8178);
|
data.setDestination(QHostAddress::LocalHost, 8178);
|
||||||
data2.setDestination(QHostAddress::LocalHost, 8178);
|
|
||||||
data3.setDestination(QHostAddress::LocalHost, 8178);
|
|
||||||
data4.setDestination(QHostAddress::LocalHost, 8178);
|
|
||||||
|
|
||||||
QString s_data = "<SET NAME=ALERT VALUE=" + QString::number(distance) + ">";
|
QString s_data = "<SET NAME=ALERT VALUE=" + QString::number(distance) + ">";
|
||||||
while(s_data.toUtf8().size() != 1024) {
|
while(s_data.toUtf8().size() != 1024) {
|
||||||
s_data += "=";
|
s_data += "=";
|
||||||
}
|
}
|
||||||
data1.setData(s_data.toUtf8());
|
data.setData(s_data.toUtf8());
|
||||||
command_socket->writeDatagram(data1);
|
command_socket->writeDatagram(data);
|
||||||
command_socket->flush();
|
command_socket->flush();
|
||||||
|
|
||||||
QString b_data = "<SET NAME=BITS_FLIPPED VALUE=" + QString((flip_bits ? "TRUE" : "FALSE")) + ">";
|
|
||||||
while(b_data.toUtf8().size() != 1024) {
|
|
||||||
b_data += "=";
|
|
||||||
}
|
|
||||||
data2.setData(b_data.toUtf8());
|
|
||||||
command_socket->writeDatagram(data2);
|
|
||||||
command_socket->flush();
|
|
||||||
|
|
||||||
QString m_data = "<SET NAME=MODE VALUE=" + mode + ">";
|
|
||||||
while(m_data.toUtf8().size() != 1024) {
|
|
||||||
m_data += "=";
|
|
||||||
}
|
|
||||||
data3.setData(m_data.toUtf8());
|
|
||||||
command_socket->writeDatagram(data3);
|
|
||||||
command_socket->flush();
|
|
||||||
|
|
||||||
QString u_data = "<SET NAME=URL VALUE=" + url + ">";
|
|
||||||
while(u_data.toUtf8().size() != 1024) {
|
|
||||||
u_data += "=";
|
|
||||||
}
|
|
||||||
data4.setData(u_data.toUtf8());
|
|
||||||
command_socket->writeDatagram(data4);
|
|
||||||
command_socket->flush();
|
|
||||||
|
|
||||||
command_socket->close();
|
command_socket->close();
|
||||||
command_socket->deleteLater();
|
|
||||||
command_socket = nullptr;
|
|
||||||
|
|
||||||
qDebug() << "Sent all Command Statements.";
|
|
||||||
emit changeWorkerMode(mode, url);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
showError("Command Socket Bind Failed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPListener::moveAppToBackground()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
service->moveAppToBackground();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::lastUpdateddatagramReceived(QByteArray data)
|
|
||||||
{
|
|
||||||
QString s_data = QString::fromUtf8(data);
|
|
||||||
qDebug() << "Main Class last updated on: " << s_data;
|
|
||||||
QDateTime time = QDateTime::fromString(s_data, "dd/MM/yy hh:mm:ss").addYears(100);
|
|
||||||
QDateTime thres_time = QDateTime::currentDateTime().addSecs(-1800);
|
|
||||||
if(time.isValid() && thres_time < time)
|
|
||||||
{
|
|
||||||
emit lastUpdatedChanged(s_data, false);
|
|
||||||
}
|
|
||||||
else if(thres_time > time && time.isValid()) {
|
|
||||||
emit lastUpdatedChanged(s_data, true);
|
|
||||||
}
|
|
||||||
else if(!time.isValid()) {
|
|
||||||
emit lastUpdatedChanged("Invalid Date", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::continueDestruction()
|
|
||||||
{
|
|
||||||
destroyed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::resetAverages()
|
|
||||||
{
|
|
||||||
averages.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::setFlipBits(bool flip_bits)
|
|
||||||
{
|
|
||||||
m_flip_bits = flip_bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::setConfig(float distance, bool flip_bits, QString mode, QString url)
|
|
||||||
{
|
|
||||||
setFlipBits(flip_bits);
|
|
||||||
setDistance(distance);
|
|
||||||
setMode(mode);
|
|
||||||
setUrl(url);
|
|
||||||
emit changeWorkerMode(mode, url);
|
|
||||||
qDebug() << "Setting config from UI completed." << flip_bits << distance << mode << url;
|
|
||||||
averages.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::socketError(QString err)
|
void UDPListener::socketError(QString err)
|
||||||
{
|
{
|
||||||
qDebug() << "Socket error received: " << err;
|
qDebug() << "Socket error received: " << err;
|
||||||
|
|
@ -157,34 +70,15 @@ 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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPListener::datagramRecieved(QByteArray data1, QByteArray data2)
|
void UDPListener::datagramRecieved(float distance)
|
||||||
{
|
{
|
||||||
std::string correct_order = "";
|
qDebug() << "Data received in main class: " << distance;
|
||||||
#ifdef Q_OS_ANDROID
|
averages.push_back(distance);
|
||||||
if(!m_flip_bits)
|
|
||||||
correct_order = "0x" + data2.toHex().toStdString();
|
|
||||||
else
|
|
||||||
correct_order = "0x" + data1.toHex().toStdString();
|
|
||||||
#else
|
|
||||||
if(!m_flip_bits)
|
|
||||||
correct_order = "0x" + data1.toHex().toStdString();
|
|
||||||
else
|
|
||||||
correct_order = "0x" + data2.toHex().toStdString();
|
|
||||||
#endif
|
|
||||||
float data = convertToFloat(correct_order);
|
|
||||||
qDebug() << "Data received in main class: " << data;
|
|
||||||
averages.push_back(data);
|
|
||||||
prev_time_point = std::chrono::high_resolution_clock::now();
|
prev_time_point = std::chrono::high_resolution_clock::now();
|
||||||
emit distanceReceived(data, QDateTime::currentDateTime().toString("dd/mm/yyyy hh:mm:ss.z ap"));
|
emit distanceReceived(distance, QDateTime::currentDateTime().toString("dd/mm/yyyy hh:mm:ss.z ap"));
|
||||||
if(averages.size() >= 5) {
|
if(averages.size() >= 5) {
|
||||||
this->m_distance = averages.get_average();
|
this->m_distance = averages.get_average();
|
||||||
emit distanceChanged();
|
emit distanceChanged();
|
||||||
|
|
@ -197,31 +91,11 @@ 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(worker, &Worker::stopped, this, &UDPListener::continueDestruction);
|
|
||||||
emit stopWorker();
|
|
||||||
while(!destroyed) {
|
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
|
||||||
}
|
|
||||||
thread->exit(0);
|
thread->exit(0);
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
|
||||||
worker->deleteLater();
|
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
|
||||||
while(thread->isRunning()) {
|
|
||||||
qDebug() << "The thread is still running.";
|
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
|
||||||
}
|
|
||||||
thread->deleteLater();
|
thread->deleteLater();
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
worker->deleteLater();
|
||||||
timer->deleteLater();
|
timer->deleteLater();
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 2000);
|
|
||||||
qDebug() << "Deinitialized UDP Listener";
|
qDebug() << "Deinitialized UDP Listener";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,195 +111,32 @@ void UDPListener::connectionTimerTimedOut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float UDPListener::convertToFloat(std::string hex)
|
|
||||||
{
|
|
||||||
uint32_t num;
|
|
||||||
sscanf(hex.c_str(), "%x", &num);
|
|
||||||
float dist = *((float*)&num);
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
Worker::Worker(QObject *parent)
|
Worker::Worker(QObject *parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::gotHttpReply(QNetworkReply *rep)
|
|
||||||
{
|
|
||||||
QByteArray m_data = rep->readAll();
|
|
||||||
rep->deleteLater();
|
|
||||||
qDebug() << "Got reply from http server";
|
|
||||||
QJsonObject top = QJsonDocument::fromJson(m_data).object();
|
|
||||||
float distance = (float ) top["water_level"].toArray()[0].toDouble();
|
|
||||||
QByteArray data, data2;
|
|
||||||
qDebug() << "Updated on: " << top["updated_on"].toString();
|
|
||||||
data = QByteArray::fromRawData((char *)&distance, sizeof(float));
|
|
||||||
char *buff = new char[4];
|
|
||||||
char *reader = (char *) &distance;
|
|
||||||
for(int i=0;i< sizeof(float) ;i++) {
|
|
||||||
qDebug() << i << "vs" << sizeof(float) - 1 - i;
|
|
||||||
buff[i] = reader[sizeof(float) - 1 - i];
|
|
||||||
}
|
|
||||||
delete[] buff;
|
|
||||||
data2 = QByteArray::fromRawData(buff, sizeof(float));
|
|
||||||
emit datagramReceived(data, data2);
|
|
||||||
emit lastUpdateddatagramReceived(top["updated_on"].toString().toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Worker::httpTimerTimeout()
|
|
||||||
{
|
|
||||||
qDebug() << "Worker httpTimer Timeout";
|
|
||||||
QNetworkRequest req;
|
|
||||||
req.setUrl(QUrl("https://unrealdragon.in/server/waterlevel"));
|
|
||||||
disconnect(manager, nullptr, nullptr, nullptr);
|
|
||||||
connect(manager, &QNetworkAccessManager::finished, this, &Worker::gotHttpReply);
|
|
||||||
manager->get(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
socket->close();
|
|
||||||
delete socket;
|
|
||||||
}
|
|
||||||
if(socket_3) {
|
|
||||||
disconnect(socket_3, nullptr, nullptr, nullptr);
|
|
||||||
socket_3->close();
|
|
||||||
delete socket_3;
|
|
||||||
}
|
|
||||||
if(httpTimer) {
|
|
||||||
disconnect(httpTimer, nullptr, nullptr, nullptr);
|
|
||||||
delete httpTimer;
|
|
||||||
}
|
|
||||||
if(manager) {
|
|
||||||
disconnect(manager, nullptr, nullptr, nullptr);
|
|
||||||
delete manager;
|
|
||||||
}
|
|
||||||
emit stopped();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Worker::run()
|
void Worker::run()
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
socket = new QUdpSocket(this);
|
socket = new QUdpSocket(this);
|
||||||
socket_2 = new QUdpSocket(this);
|
|
||||||
socket_3 = new QUdpSocket(this);
|
|
||||||
httpTimer = new QTimer(this);
|
|
||||||
manager = new QNetworkAccessManager(this);
|
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
// If it is android use it as a command socket;
|
bool bind = socket->bind(QHostAddress::Any, 8180);
|
||||||
bool bind = socket->bind(QHostAddress::LocalHost, 8180, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
|
|
||||||
bool bind2 = socket_2->bind(QHostAddress::LocalHost, 8185, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
|
|
||||||
bool bind3 = socket_3->bind(QHostAddress::LocalHost, 8186, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress);
|
|
||||||
#else
|
#else
|
||||||
// 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);
|
||||||
bool bind2 = true;
|
|
||||||
#endif
|
#endif
|
||||||
if(!bind || !bind2 || !bind3)
|
if(!bind)
|
||||||
{
|
{
|
||||||
qDebug() << "UI Worker socket bind failed" << bind << socket->errorString();
|
qDebug() << "UI Worker socket bind failed" << bind << socket->errorString();
|
||||||
qDebug() << "UI Worker socket bind failed" << bind2 << socket_2->errorString();
|
|
||||||
qDebug() << "UI Worker socket bind failed" << bind3 << socket_3->errorString();
|
|
||||||
emit socketError(socket->errorString());
|
emit socketError(socket->errorString());
|
||||||
emit socketError(socket_2->errorString());
|
|
||||||
emit socketError(socket_3->errorString());
|
|
||||||
qApp->exit(-1);
|
|
||||||
}
|
}
|
||||||
connect(httpTimer, &QTimer::timeout, this, &Worker::httpTimerTimeout);
|
|
||||||
connect(socket, &QUdpSocket::readyRead, this, &Worker::socketDataReceived);
|
connect(socket, &QUdpSocket::readyRead, this, &Worker::socketDataReceived);
|
||||||
connect(socket_2, &QUdpSocket::readyRead, this, &Worker::socket2DataReceived);
|
|
||||||
connect(socket_3, &QUdpSocket::readyRead, this, &Worker::socket3DataReceived);
|
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
qDebug() << "Waiting for message from service.";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Worker::changeMode(QString mode, QString url)
|
|
||||||
{
|
|
||||||
qDebug() << "Worker changing mode: " << mode << url;
|
|
||||||
this->mode = mode;
|
|
||||||
this->url = url;
|
|
||||||
if(mode == "http" && QSysInfo::productType() != "android") {
|
|
||||||
httpTimer->setInterval(2000);
|
|
||||||
httpTimer->setSingleShot(false);
|
|
||||||
httpTimer->start();
|
|
||||||
}
|
|
||||||
else if(mode == "udp") {
|
|
||||||
httpTimer->stop();
|
|
||||||
socketDataReceived();
|
|
||||||
}
|
|
||||||
if(socket) {
|
|
||||||
if(socket->hasPendingDatagrams()) {
|
|
||||||
socketDataReceived();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(socket_2) {
|
|
||||||
if(socket_2->hasPendingDatagrams()) {
|
|
||||||
socket2DataReceived();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(socket_3) {
|
|
||||||
if(socket_3->hasPendingDatagrams()) {
|
|
||||||
socket3DataReceived();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Worker::socket3DataReceived()
|
|
||||||
{
|
|
||||||
if(socket_3->hasPendingDatagrams()) {
|
|
||||||
while(this->mode == "" && this->url == "") {
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
// qDebug() << "Worker is waiting for mode to be set.";
|
|
||||||
}
|
|
||||||
size_t data_size = socket_3->pendingDatagramSize();
|
|
||||||
qDebug() << "Socket 3 has pending data: " << data_size;
|
|
||||||
if(data_size < 100000) {
|
|
||||||
char buff[data_size];
|
|
||||||
socket_3->readDatagram(buff, data_size);
|
|
||||||
QByteArray data = QByteArray::fromRawData(buff, data_size);
|
|
||||||
if(QString::fromUtf8(data) == "<SET>") {
|
|
||||||
qDebug() << "Data Received from Service Threads.";
|
|
||||||
emit sendConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Worker::socket2DataReceived()
|
|
||||||
{
|
|
||||||
if(socket_2->hasPendingDatagrams()) {
|
|
||||||
if(mode == "http") {
|
|
||||||
size_t data_size = socket_2->pendingDatagramSize();
|
|
||||||
qDebug() << "Socket 2 has pending data: " << data_size;
|
|
||||||
char buff[data_size];
|
|
||||||
socket_2->readDatagram(buff, data_size);
|
|
||||||
QByteArray data = QByteArray::fromRawData(buff, data_size);
|
|
||||||
emit lastUpdateddatagramReceived(data);
|
|
||||||
}
|
|
||||||
else if(mode == "udp") {
|
|
||||||
qDebug() << "Last Updated on Socket data received in udp mode ignoring it.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
qDebug() << "Mode is not set in socket 2";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::socketDataReceived()
|
void Worker::socketDataReceived()
|
||||||
{
|
{
|
||||||
if(socket->hasPendingDatagrams()) {
|
if(socket->hasPendingDatagrams()) {
|
||||||
if(mode == "udp" || (mode == "http" && QSysInfo::productType() == "android")) {
|
|
||||||
qDebug() << "Socket has pending data: " << socket->pendingDatagramSize();
|
qDebug() << "Socket has pending data: " << socket->pendingDatagramSize();
|
||||||
char buff[4] = {0x00, 0x00, 0x00, 0x00};
|
char buff[4] = {0x00, 0x00, 0x00, 0x00};
|
||||||
socket->readDatagram(buff, 4);
|
socket->readDatagram(buff, 4);
|
||||||
|
|
@ -435,41 +146,16 @@ void Worker::socketDataReceived()
|
||||||
ch[i] = buff[3-i];
|
ch[i] = buff[3-i];
|
||||||
}
|
}
|
||||||
auto data2 = QByteArray(ch,4);
|
auto data2 = QByteArray(ch,4);
|
||||||
std::string correct_order = "";
|
#ifdef Q_OS_ANDROID
|
||||||
|
std::string correct_order = "0x" + data2.toHex().toStdString();
|
||||||
|
#else
|
||||||
|
std::string correct_order = "0x" + data2.toHex().toStdString();
|
||||||
|
#endif
|
||||||
qDebug() << "Distance received: " << correct_order;
|
qDebug() << "Distance received: " << correct_order;
|
||||||
emit datagramReceived(data, data2);
|
uint32_t num;
|
||||||
}
|
sscanf(correct_order.c_str(), "%x", &num);
|
||||||
else if(mode == "http") {
|
float dist = *((float*)&num);
|
||||||
qDebug() << "Socket data received in http mode ignoring it.";
|
qDebug() << "Float is: " << dist;
|
||||||
}
|
emit datagramReceived(dist);
|
||||||
else {
|
|
||||||
qDebug() << "Mode is not set in socket.";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString UDPListener::mode() const
|
|
||||||
{
|
|
||||||
return m_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::setMode(const QString &newMode)
|
|
||||||
{
|
|
||||||
if (m_mode == newMode)
|
|
||||||
return;
|
|
||||||
m_mode = newMode;
|
|
||||||
emit modeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString UDPListener::url() const
|
|
||||||
{
|
|
||||||
return m_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPListener::setUrl(const QString &newUrl)
|
|
||||||
{
|
|
||||||
if (m_url == newUrl)
|
|
||||||
return;
|
|
||||||
m_url = newUrl;
|
|
||||||
emit urlChanged();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,45 +8,19 @@
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#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;
|
||||||
QUdpSocket *socket_2 = nullptr;
|
|
||||||
QUdpSocket *socket_3 = nullptr;
|
|
||||||
QString mode = "";
|
|
||||||
QString url = "";
|
|
||||||
QNetworkAccessManager *manager = nullptr;
|
|
||||||
QTimer *httpTimer = nullptr;
|
|
||||||
public:
|
public:
|
||||||
explicit Worker(QObject *parent = nullptr);
|
explicit Worker(QObject *parent = nullptr);
|
||||||
signals:
|
signals:
|
||||||
void sendConfig();
|
|
||||||
void stopped();
|
|
||||||
void socketError(QString error);
|
void socketError(QString error);
|
||||||
void lastUpdateddatagramReceived(QByteArray data);
|
void datagramReceived(float distance);
|
||||||
void datagramReceived(QByteArray data, QByteArray data2);
|
|
||||||
public slots:
|
public slots:
|
||||||
void gotHttpReply(QNetworkReply *rep);
|
|
||||||
void httpTimerTimeout();
|
|
||||||
void stop();
|
|
||||||
void run();
|
void run();
|
||||||
void changeMode(QString mode, QString url);
|
|
||||||
private slots:
|
private slots:
|
||||||
void socket3DataReceived();
|
|
||||||
void socket2DataReceived();
|
|
||||||
void socketDataReceived();
|
void socketDataReceived();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,51 +29,25 @@ class UDPListener : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
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)
|
||||||
Q_PROPERTY(QString mode READ mode WRITE setMode NOTIFY modeChanged FINAL)
|
|
||||||
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged FINAL)
|
|
||||||
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);
|
||||||
QString mode() const;
|
|
||||||
void setMode(const QString &newMode);
|
|
||||||
|
|
||||||
QString url() const;
|
|
||||||
void setUrl(const QString &newUrl);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void lastUpdatedChanged(QString last_updated, bool warn);
|
|
||||||
void stopWorker();
|
|
||||||
void showError(QString err);
|
void showError(QString err);
|
||||||
void distanceChanged();
|
void distanceChanged();
|
||||||
void startWorker();
|
void startWorker();
|
||||||
void connected();
|
void connected();
|
||||||
void disconnected();
|
void disconnected();
|
||||||
void distanceReceived(double dist, QString timestamp);
|
void distanceReceived(double dist, QString timestamp);
|
||||||
void changeWorkerMode(QString mode, QString url);
|
|
||||||
void modeChanged();
|
|
||||||
void initLoadFinished();
|
|
||||||
void urlChanged();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sendConfigOnSet();
|
void setAlert(float distance);
|
||||||
void moveAppToBackground();
|
|
||||||
void lastUpdateddatagramReceived(QByteArray data);
|
|
||||||
void continueDestruction();
|
|
||||||
void resetAverages();
|
|
||||||
void setFlipBits(bool flip_bits);
|
|
||||||
void setConfig(float distance, bool flip_bits, QString mode, QString url);
|
|
||||||
void socketError(QString err);
|
void socketError(QString err);
|
||||||
void startService();
|
void startService();
|
||||||
void datagramRecieved(QByteArray data, QByteArray data2);
|
void datagramRecieved(float distance);
|
||||||
private slots:
|
private slots:
|
||||||
void destroy();
|
void destroy();
|
||||||
void connectionTimerTimedOut();
|
void connectionTimerTimedOut();
|
||||||
float convertToFloat(std::string hex);
|
|
||||||
private:
|
private:
|
||||||
QUdpSocket *command_socket = nullptr;
|
QUdpSocket *command_socket = nullptr;
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> prev_time_point;
|
std::chrono::time_point<std::chrono::high_resolution_clock> prev_time_point;
|
||||||
|
|
@ -108,9 +56,6 @@ private:
|
||||||
Worker *worker = nullptr;
|
Worker *worker = nullptr;
|
||||||
QThread *thread = nullptr;
|
QThread *thread = nullptr;
|
||||||
QTimer *timer = nullptr;
|
QTimer *timer = nullptr;
|
||||||
bool m_flip_bits;
|
|
||||||
QString m_mode;
|
|
||||||
QString m_url;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UDPLISTENER_H
|
#endif // UDPLISTENER_H
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue