Add more functions
This commit is contained in:
@@ -10,7 +10,7 @@ AudioFile03 = pinkNoiseWav.wav
|
||||
AudioFile04 = 04.mp3
|
||||
AudioFile05 = 05.mp3
|
||||
AudioVolumeOutput = 100
|
||||
SerialPort = /dev/ttyUSB0
|
||||
SerialPort = /dev/ttyAMA0
|
||||
SerialBaudRate = 9600
|
||||
PanTiltID = 1
|
||||
WebUsername = admin
|
||||
|
||||
@@ -40,23 +40,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!--<div class="container-fluid container4">-->
|
||||
<!-- <div class="row">-->
|
||||
<!-- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8 border-1">-->
|
||||
<!-- <h1 class="hr-lines">Bird Deterrent System</h1>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-4">-->
|
||||
<!-- <div class="container">-->
|
||||
<!-- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 outside-logout">-->
|
||||
<!-- <form action="/logout" method="get">-->
|
||||
<!-- <button class="btn btn-outline-light" type="submit">Logout</button>-->
|
||||
<!-- </form>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!--</div>-->
|
||||
<!-- SECTION 1-->
|
||||
|
||||
|
||||
<!-- SECTION 2 -->
|
||||
<div class="container-fluid container3">
|
||||
@@ -66,13 +50,43 @@
|
||||
<img id="camerastream" src="public/images/not-available.png" class="img-cctv class100" alt="">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 col-sm-6 col-md-8 col-lg-8 col-xl-8">
|
||||
<div class="col-12 col-sm-4 col-md-4 col-lg-4 col-xl-4">
|
||||
<p id="streaming_status">No Status</p>
|
||||
</div>
|
||||
<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="quality_video" onchange="change_video_quality()">
|
||||
<label class="form-check-label" for="quality_video">High Quality Video</label>
|
||||
<div class="col-12 col-sm-4 col-md-5 col-lg-5 col-xl-5">
|
||||
<!-- <p id="system_information"> System Information </p>-->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="fa-solid fa-microchip icon-system"></span>
|
||||
<p id="cpu_usage" class="padleft">100 %</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="fa-solid fa-temperature-half icon-system"></span>
|
||||
<p id="cpu_temperature" class="padleft">55 °C</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="fa-solid fa-memory icon-system"></span>
|
||||
<p id="ram_usage" class="padleft">15 %</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-4 col-md-3 col-lg-3 col-xl-3">
|
||||
<!-- <div class="form-check form-switch">-->
|
||||
<!-- <input class="form-check-input" type="checkbox" role="switch" id="quality_video" onchange="change_video_quality()">-->
|
||||
<!-- <label class="form-check-label" for="quality_video">HQ</label>-->
|
||||
<!-- </div>-->
|
||||
<div class="container align-right">
|
||||
<label for="quality_video" class="toggle-label">LQ</label>
|
||||
<input type="checkbox" class="toggle-switch" id="quality_video" onchange="change_video_quality()">
|
||||
<label for="quality_video" class="toggle-label">HQ</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,10 +14,32 @@ let camerastream;
|
||||
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(){
|
||||
camerastream = document.getElementById("camerastream");
|
||||
let files = [null,null,null,null,null];
|
||||
|
||||
setInterval(function (){
|
||||
let getbase64handle;
|
||||
let getsysteminfohandle;
|
||||
|
||||
window.addEventListener("unload",function (){
|
||||
clearInterval(getbase64handle);
|
||||
clearInterval(getsysteminfohandle);
|
||||
if (ws.readyState === WebSocket.OPEN){
|
||||
ws.send(JSON.stringify({
|
||||
command: "STOP AUDIO",
|
||||
data: 0
|
||||
}));
|
||||
|
||||
// wait a while
|
||||
const start = Date.now();
|
||||
while(Date.now()-start<200){}
|
||||
}
|
||||
|
||||
ws.close();
|
||||
})
|
||||
|
||||
window.addEventListener("load", function (){
|
||||
camerastream = document.getElementById("camerastream");
|
||||
// Update camera stream every 50ms / 20fps
|
||||
getbase64handle = setInterval(function (){
|
||||
if (ws.readyState === WebSocket.OPEN){
|
||||
ws.send(JSON.stringify({
|
||||
command: "GET BASE64",
|
||||
@@ -25,7 +47,16 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
}));
|
||||
|
||||
} else update_camerastream(null);
|
||||
},10);
|
||||
},1000/15);
|
||||
|
||||
getsysteminfohandle = setInterval(function (){
|
||||
if (ws.readyState === WebSocket.OPEN){
|
||||
ws.send(JSON.stringify({
|
||||
command: "GET SYSTEM INFO",
|
||||
data: 0
|
||||
}));
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
ws = new WebSocket("/ws");
|
||||
|
||||
@@ -49,6 +80,10 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
command: "GET RESOLUTION",
|
||||
data: 0
|
||||
}));
|
||||
ws.send(JSON.stringify({
|
||||
command: "GET AUDIOFILES",
|
||||
data: 0
|
||||
}))
|
||||
|
||||
}
|
||||
ws.onmessage = function(event){
|
||||
@@ -63,7 +98,10 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
update_camerastream(dx.data);
|
||||
} else update_camerastream(null);
|
||||
if (dx.additional && dx.additional.length>0){
|
||||
$('#streaming_status').html(dx.additional);
|
||||
let stat = JSON.parse(dx.additional);
|
||||
if (Array.isArray(stat) && stat.length === 3){
|
||||
$('#streaming_status').html("Streaming at "+stat[0]+"x"+stat[1]+" "+stat[2]+"fps");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "SET VOLUME":
|
||||
@@ -75,15 +113,13 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
break;
|
||||
case "GET MAX ZOOM":
|
||||
console.log("Get Max Zoom: "+dx.data);
|
||||
$('#zoom')
|
||||
.attr("max", dx.data)
|
||||
.attr("min", 1);
|
||||
|
||||
|
||||
let zoom = document.getElementById("zoom");
|
||||
zoom.min = 1;
|
||||
zoom.max = dx.data;
|
||||
break;
|
||||
case "GET ZOOM":
|
||||
document.getElementById("zoom").value = dx.data;
|
||||
console.log("Get Zoom: "+dx.data);
|
||||
$('#zoom').val(dx.data);
|
||||
break;
|
||||
case "GET RESOLUTION":
|
||||
console.log("Get Resolution: "+dx.data);
|
||||
@@ -114,11 +150,60 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
break;
|
||||
case "STOP AUDIO":
|
||||
console.log("Stop Audio");
|
||||
$('#status_player').html("Stop Playback");
|
||||
document.getElementById("status_player").innerHTML = "Stop Playback";
|
||||
break;
|
||||
case 'SET VIDEO QUALITY':
|
||||
console.log("Set Video Quality: "+dx.data);
|
||||
break;
|
||||
case "GET SYSTEM INFO":
|
||||
//console.log("Get System Info: "+dx.data);
|
||||
/**
|
||||
* @type {{cpu_temperature: string, ram_usage: string, cpu: string, cpu0: string, cpu1: string, cpu2: string, cpu3: string}} systeminfo
|
||||
*/
|
||||
let systeminfo = JSON.parse(dx.data);
|
||||
if (systeminfo.cpu_temperature && systeminfo.cpu_temperature.length>0) $('#cpu_temperature').html(`${systeminfo.cpu_temperature} °C`);
|
||||
if (systeminfo.cpu && systeminfo.cpu.length>0) $('#cpu_usage').html(`${systeminfo.cpu} %`);
|
||||
if (systeminfo.ram_usage && systeminfo.ram_usage.length>0) $('#ram_usage').html(`${systeminfo.ram_usage} %`);
|
||||
break;
|
||||
case "GET AUDIOFILES":
|
||||
console.log("Get Audio Files: "+dx.data);
|
||||
let audiofiles = JSON.parse(dx.data);
|
||||
if (audiofiles.preset1 && audiofiles.preset1.length>0 && audiofiles.preset1!== "null") {
|
||||
files[0] = audiofiles.preset1;
|
||||
play_on(1);
|
||||
} else {
|
||||
files[0] = null;
|
||||
play_off(1);
|
||||
}
|
||||
if (audiofiles.preset2 && audiofiles.preset2.length>0 && audiofiles.preset2!== "null") {
|
||||
files[1] = audiofiles.preset2;
|
||||
play_on(2);
|
||||
} else {
|
||||
files[1] = null;
|
||||
play_off(2);
|
||||
}
|
||||
if (audiofiles.preset3 && audiofiles.preset3.length>0 && audiofiles.preset3!== "null") {
|
||||
files[2] = audiofiles.preset3;
|
||||
play_on(3);
|
||||
} else {
|
||||
files[2] = null;
|
||||
play_off(3);
|
||||
}
|
||||
if (audiofiles.preset4 && audiofiles.preset4.length>0 && audiofiles.preset4!== "null") {
|
||||
files[3] = audiofiles.preset4;
|
||||
play_on(4);
|
||||
} else {
|
||||
files[3] = null;
|
||||
play_off(4);
|
||||
}
|
||||
if (audiofiles.preset5 && audiofiles.preset5.length>0 && audiofiles.preset5!== "null") {
|
||||
files[4] = audiofiles.preset5;
|
||||
play_on(5);
|
||||
} else {
|
||||
files[4] = null;
|
||||
play_off(5);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -132,7 +217,9 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
|
||||
set_pan_speed(32);
|
||||
set_tilt_speed(32);
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update camera stream
|
||||
@@ -176,7 +263,9 @@ function show_stop_and_hide_play(index){
|
||||
}
|
||||
|
||||
function allplay(){
|
||||
for (let i = 0; i < 5; i++) play_on(i+1);
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (files[i]) play_on(i+1);
|
||||
}
|
||||
}
|
||||
|
||||
function play_button(index){
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
<h5 class="text-md-center">Audio Files</h5>
|
||||
</div>
|
||||
<div class="card-body bg-gray">
|
||||
<form action="/setting/audiofile" method="post">
|
||||
<!-- PRESET 1-->
|
||||
<div class="row mt--2">
|
||||
<div class="col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6">
|
||||
@@ -112,10 +111,9 @@
|
||||
<div class="row mt-2">
|
||||
<div class="col-6"></div>
|
||||
<div class="col-6">
|
||||
<button id="save_audio" type="submit" class="btn btn-primary class100" onclick="save_audio()">SAVE</button>
|
||||
<button id="save_audio" class="btn btn-primary class100" onclick="save_audio()">SAVE</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -130,7 +128,7 @@
|
||||
<p> Upload audio files</p>
|
||||
</div>
|
||||
<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-4">
|
||||
<input class="form-control" type="file" name="file" title="Select Audio File">
|
||||
<input class="form-control" type="file" name="file" required title="Select Audio File">
|
||||
</div>
|
||||
<div class="col-6 col-sm-6 col-md-2 col-lg-2 col-xl-2">
|
||||
<button id="uploadd_file" type="submit" class="btn btn-dark class100">Upload</button>
|
||||
@@ -146,13 +144,12 @@
|
||||
<h5 class="text-center">Camera</h5>
|
||||
</div>
|
||||
<div class="card-body bg-gray">
|
||||
<form action="/setting/camera" method="post">
|
||||
<div class="row mt-2">
|
||||
<div class="col-6">
|
||||
<p>IP Address</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input id="setting_ip" class="form-control" title="IP Address">
|
||||
<input id="setting_ip" name="ip" class="form-control" title="IP Address">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
@@ -160,7 +157,7 @@
|
||||
<p>Port</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input id="setting_port" class="form-control" title="Port">
|
||||
<input id="setting_port" name="port" class="form-control" title="Port">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -169,7 +166,7 @@
|
||||
<p>Username</p>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input id="setting_username" class="form-control" title="Username">
|
||||
<input id="setting_username" name="username" class="form-control" title="Username">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -179,7 +176,7 @@
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="input-group">
|
||||
<input type="password" id="setting_password" class="form-control" title="Password">
|
||||
<input type="password" id="setting_password" name="password" class="form-control" title="Password">
|
||||
<span class="input-group-text" onclick="cameraPassword()">
|
||||
<i class="fa-solid fa-eye" id="icon_camera"></i>
|
||||
</span>
|
||||
@@ -189,10 +186,9 @@
|
||||
<div class="row mt-2">
|
||||
<div class="col-6"></div>
|
||||
<div class="col-6">
|
||||
<button id="save_camera" type="submit" class="btn btn-primary class100" onclick="save_camera()">SAVE</button>
|
||||
<button id="save_camera" class="btn btn-primary class100" onclick="save_camera()">SAVE</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -201,7 +197,6 @@
|
||||
<h5 class="text-center">Login</h5>
|
||||
</div>
|
||||
<div class="card-body bg-gray">
|
||||
<form action="/setting/weblogin" method="post">
|
||||
<div class="row mt-2">
|
||||
<div class="col-6">
|
||||
<p>Username</p>
|
||||
@@ -239,10 +234,9 @@
|
||||
<div class="row mt-2">
|
||||
<div class="col-6"></div>
|
||||
<div class="col-6">
|
||||
<button id="save_login" type="submit" class="btn btn-primary class100" onclick="save_login()">SAVE</button>
|
||||
<button id="save_login" class="btn btn-primary class100" onclick="save_login()">SAVE</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,7 +54,14 @@ function fill_select(index, values){
|
||||
*/
|
||||
let preset = document.getElementById("preset"+index);
|
||||
preset.innerHTML = "";
|
||||
|
||||
if (values!=null && values.length>0){
|
||||
// add empty option
|
||||
let option = document.createElement("option");
|
||||
option.value = "";
|
||||
option.innerText = "";
|
||||
preset.appendChild(option);
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const element = values[i];
|
||||
let option = document.createElement("option");
|
||||
@@ -109,3 +116,90 @@ function showConfirm() {
|
||||
icon.classList.add('fa-eye');
|
||||
}
|
||||
}
|
||||
|
||||
function save_audio(){
|
||||
let preset1 = $('#preset1').val();
|
||||
let preset2 = $('#preset2').val();
|
||||
let preset3 = $('#preset3').val();
|
||||
let preset4 = $('#preset4').val();
|
||||
let preset5 = $('#preset5').val();
|
||||
|
||||
if (confirm("Are you sure want to change Audio Preset ?")){
|
||||
fetch("/setting/audiofile", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: new URLSearchParams({preset1: preset1, preset2: preset2, preset3: preset3, preset4: preset4, preset5: preset5})
|
||||
}).then(resp => {
|
||||
if (resp.status === 200) {
|
||||
alert("Success");
|
||||
} else {
|
||||
resp.text().then(text=>alert("Failed to change Audio Preset : "+text));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function save_camera(){
|
||||
let ip = $('#setting_ip').val();
|
||||
let port = $('#setting_port').val();
|
||||
let username = $('#setting_username').val();
|
||||
let password = $('#setting_password').val();
|
||||
|
||||
if (confirm("Are you sure want to change Camera Information ?")){
|
||||
fetch("/setting/camera", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: new URLSearchParams({ip: ip, port: port, username: username, password: password})
|
||||
}).then(resp => {
|
||||
if (resp.status === 200) {
|
||||
alert("Success");
|
||||
} else {
|
||||
resp.text().then(text => {
|
||||
alert("Failed to change Camera Information : "+text);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function save_login(){
|
||||
let username = $('#login_username').val();
|
||||
let password = $('#edit_password').val();
|
||||
let confirmpassword = $('#confirm_password').val();
|
||||
if (username.length === 0){
|
||||
alert("Username cannot be empty");
|
||||
return;
|
||||
}
|
||||
if (password.length === 0){
|
||||
alert("Password cannot be empty");
|
||||
return;
|
||||
}
|
||||
if (password !== confirmpassword){
|
||||
alert("Password not match");
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirm("Are you sure want to change Web Login Information ?")){
|
||||
fetch("/setting/weblogin", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: new URLSearchParams({username: username, password: password})
|
||||
}).then(resp => {
|
||||
if (resp.status === 200) {
|
||||
alert("Success");
|
||||
} else {
|
||||
resp.text().then(text => {
|
||||
alert("Failed to change Web Login Information : "+text);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#Fri Nov 08 16:52:01 WIB 2024
|
||||
#Mon Nov 11 16:04:42 WIB 2024
|
||||
AudioFile01=elangWav.wav
|
||||
AudioFile02=gunshotsWav.wav
|
||||
AudioFile03=pinkNoiseWav.wav
|
||||
AudioFile04=04.mp3
|
||||
AudioFile05=05.mp3
|
||||
AudioFile04=
|
||||
AudioFile05=null
|
||||
AudioVolumeOutput=100
|
||||
Camera_Rtsp_path=/axis-media/media.amp
|
||||
Camera_ip=192.168.10.17
|
||||
@@ -12,13 +12,8 @@ Camera_port=80
|
||||
Camera_user=root
|
||||
PanTiltID=1
|
||||
SerialBaudRate=9600
|
||||
SerialPort=/dev/ttyUSB0
|
||||
SerialPort=/dev/ttyAMA0
|
||||
WebHost=0.0.0.0
|
||||
WebPassword=bandara
|
||||
WebPort=8080
|
||||
WebUsername=admin
|
||||
audiofile1=
|
||||
audiofile2=
|
||||
audiofile3=
|
||||
audiofile4=
|
||||
audiofile5=
|
||||
|
||||
193
pom.xml
193
pom.xml
@@ -8,11 +8,188 @@
|
||||
<artifactId>BirdStrikeSoetta</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.10</version>
|
||||
<version>1.5.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>leptonica</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>leptonica-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>artoolkitplus</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>artoolkitplus-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>libdc1394</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>libdc1394-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>libfreenect</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>libfreenect-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>libfreenect2</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>libfreenect2-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>flycapture</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>flycapture-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>librealsense</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>librealsense-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>librealsense2</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>librealsense2-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>videoinput</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>videoinput-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>tesseract</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>tesseract-platform</artifactId>
|
||||
</exclusion>
|
||||
<!-- platform dibuangin semua, kemudian tambah sendiri linux-arm64, windows-x86_64, linux-x86_64 -->
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv-platform</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg-platform</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- manual tambah untuk platform windows-x86_64 -->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.6.0-1.5.8</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>1.5.8</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas</artifactId>
|
||||
<version>0.3.21-1.5.8</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>5.1.2-1.5.8</version>
|
||||
<classifier>windows-x86_64</classifier>
|
||||
</dependency>
|
||||
<!-- manual tambah untuk platform linux-arm64-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.6.0-1.5.8</version>
|
||||
<classifier>linux-arm64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>1.5.8</version>
|
||||
<classifier>linux-arm64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas</artifactId>
|
||||
<version>0.3.21-1.5.8</version>
|
||||
<classifier>linux-arm64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>5.1.2-1.5.8</version>
|
||||
<classifier>linux-arm64</classifier>
|
||||
</dependency>
|
||||
<!-- manual tambah untuk platform linux-x86_64
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>opencv</artifactId>
|
||||
<version>4.9.0-1.5.10</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacpp</artifactId>
|
||||
<version>1.5.10</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>openblas</artifactId>
|
||||
<version>0.3.26-1.5.10</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg</artifactId>
|
||||
<version>6.1.1-1.5.10</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.javalin</groupId>
|
||||
<artifactId>javalin</artifactId>
|
||||
@@ -52,6 +229,11 @@
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
@@ -60,4 +242,13 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>kr.motd.maven</groupId>
|
||||
<artifactId>os-maven-plugin</artifactId>
|
||||
<version>1.7.0</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,14 +1,15 @@
|
||||
package Audio;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
public class AudioPlayer {
|
||||
Bass bass;
|
||||
int deviceid = -1;
|
||||
boolean inited = false;
|
||||
private final Bass bass;
|
||||
private int deviceid = -1;
|
||||
@Getter private boolean inited = false;
|
||||
|
||||
int playbackhandle = 0;
|
||||
float playbackvolume = 1.0f;
|
||||
@@ -48,13 +49,49 @@ public class AudioPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get BASS_DEVICEINFO for a device
|
||||
* @param device device id
|
||||
* @return BASS_DEVICEINFO object or null if failed
|
||||
*/
|
||||
public Bass.BASS_DEVICEINFO GetDeviceInfo(int device){
|
||||
Bass.BASS_DEVICEINFO info = new Bass.BASS_DEVICEINFO();
|
||||
if (bass.BASS_GetDeviceInfo(device, info)){
|
||||
return info;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find Device ID with Name
|
||||
* @param name device name
|
||||
* @return device id, or -1 if not found
|
||||
*/
|
||||
public int FindDeviceIDWithName(String name){
|
||||
int result = -1;
|
||||
int ii = 1;
|
||||
while(true){
|
||||
Bass.BASS_DEVICEINFO info = new Bass.BASS_DEVICEINFO();
|
||||
if (bass.BASS_GetDeviceInfo(ii, info)){
|
||||
if (info.name.contains(name)){
|
||||
result = ii;
|
||||
break;
|
||||
}
|
||||
ii++;
|
||||
} else {
|
||||
// gak ada lagi
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open Output Device
|
||||
* @param device device id, starts from 1
|
||||
* @param freq output frequency
|
||||
* @return true if success
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public boolean OpenDevice(int device, int freq){
|
||||
int flag = Bass.BASS_DEVICE_REINIT | Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_MONO | Bass.BASS_DEVICE_FREQ;
|
||||
boolean success = bass.BASS_Init(device, freq, flag);
|
||||
@@ -69,7 +106,8 @@ public class AudioPlayer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Master Volume
|
||||
* Set Master Output Volume
|
||||
* Master Output Volume related to the system volume (Alsamixer on Linux, Volume Mixer on Windows)
|
||||
* @param value volume value, 0-100
|
||||
*/
|
||||
public void setMasterVolume(int value){
|
||||
@@ -84,7 +122,8 @@ public class AudioPlayer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Master Volume
|
||||
* Get Master Output Volume
|
||||
* Master Output Volume related to the system volume (Alsamixer on Linux, Volume Mixer on Windows)
|
||||
* @return 0 - 100, or -1 if failed
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@@ -99,6 +138,11 @@ public class AudioPlayer {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Playback Volume
|
||||
* is the volume of the currently playing audio file
|
||||
* @return 0 - 100
|
||||
*/
|
||||
public int getPlaybackvolume(){
|
||||
if (playbackvolume<0)
|
||||
return 0;
|
||||
@@ -108,6 +152,11 @@ public class AudioPlayer {
|
||||
return (int)(playbackvolume*100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Playback Volume
|
||||
* is the volume of the currently playing audio file
|
||||
* @param value 0 - 100
|
||||
*/
|
||||
public void setPlaybackvolume(int value){
|
||||
if (value<0) value = 0;
|
||||
if (value>100) value = 100;
|
||||
@@ -119,11 +168,17 @@ public class AudioPlayer {
|
||||
|
||||
private float lastplaybackvolume = 1.0f;
|
||||
|
||||
/**
|
||||
* Set Playback Volume to 0
|
||||
*/
|
||||
public void Mute(){
|
||||
lastplaybackvolume = playbackvolume;
|
||||
setPlaybackvolume(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Playback Volume to last volume before Mute
|
||||
*/
|
||||
public void Unmute(){
|
||||
setPlaybackvolume((int)lastplaybackvolume*100);
|
||||
}
|
||||
@@ -164,6 +219,12 @@ public class AudioPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Play Audio File
|
||||
* @param prop AudioFileProperties object to play
|
||||
* @param looping set true to loop the audio file
|
||||
* @param event PlaybackEvent object to handle playback event
|
||||
*/
|
||||
public void PlayAudioFile(AudioFileProperties prop, boolean looping, PlaybackEvent event){
|
||||
if (inited){
|
||||
if (prop!=null){
|
||||
|
||||
@@ -9,6 +9,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bytedeco.javacv.Frame;
|
||||
import org.bytedeco.javacv.FrameGrabber;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
public class GrabbingTask implements Runnable {
|
||||
@Setter private Consumer<String> onMessageUpdate;
|
||||
@@ -16,13 +17,13 @@ public class GrabbingTask implements Runnable {
|
||||
@Setter private Consumer<Frame> onLQFrameUpdate;
|
||||
@Setter private Consumer<String> onHQBase64Update;
|
||||
@Setter private Consumer<String> onLQBase64Update;
|
||||
@Getter private int CaptureFPS = 0;
|
||||
|
||||
private final AtomicBoolean isGrabbing;
|
||||
private final FrameGrabber grabber;
|
||||
@Getter private final int lowquality_width = 640;
|
||||
@Getter private final int lowquality_height = 360;
|
||||
|
||||
|
||||
private void updateMessage(String message) {
|
||||
if (onMessageUpdate != null) {
|
||||
onMessageUpdate.accept(message);
|
||||
@@ -68,15 +69,14 @@ public class GrabbingTask implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
public void Stop(){
|
||||
isGrabbing.set(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
isGrabbing.set(true);
|
||||
while (isGrabbing.get()) {
|
||||
try {
|
||||
private void grabprocess() throws Exception{
|
||||
grabber.flush();
|
||||
Frame fr =grabber.grab();
|
||||
|
||||
if (fr!=null){
|
||||
updateHQFrame(fr);
|
||||
updateHQBase64(SomeCodes.FrameToBase64(fr));
|
||||
@@ -84,11 +84,29 @@ public class GrabbingTask implements Runnable {
|
||||
updateLQFrame(resized);
|
||||
updateLQBase64(SomeCodes.FrameToBase64(resized));
|
||||
} else updateMessage("Grabber returned null frame");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
isGrabbing.set(true);
|
||||
Logger.info("Grabbing Task started");
|
||||
double fps = grabber.getFrameRate();
|
||||
Logger.info("Grabber framerate = {}", fps);
|
||||
long starttick = System.currentTimeMillis();
|
||||
while (isGrabbing.get()) {
|
||||
|
||||
long elapsed = System.currentTimeMillis() - starttick;
|
||||
starttick = System.currentTimeMillis();
|
||||
//Logger.info("Elapsed time = {} ms", elapsed);
|
||||
if (elapsed>0) CaptureFPS = (int) (1000 / elapsed);
|
||||
try{
|
||||
Thread.yield();
|
||||
grabprocess();
|
||||
} catch (Exception e){
|
||||
updateMessage("Error grabbing frame: " + e.getMessage());
|
||||
Logger.error("Error grabbing frame: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Logger.info("Grabbing Task stopped");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ package Camera;
|
||||
import com.fazecast.jSerialComm.SerialPort;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* Pan Tilt Controller
|
||||
* Using PelcoD protocol
|
||||
* Source : https://www.commfront.com/pages/pelco-d-protocol-tutorial
|
||||
* Source : <a href="https://www.commfront.com/pages/pelco-d-protocol-tutorial">PelcoD Tutorial</a>
|
||||
*/
|
||||
public class PanTiltController {
|
||||
private final SerialPort serialPort;
|
||||
private SerialPort serialPort;
|
||||
private final byte cameraid;
|
||||
/**
|
||||
* Open Pan Tilt Controller
|
||||
@@ -17,21 +18,38 @@ public class PanTiltController {
|
||||
* @param baudrate baudrate used
|
||||
*/
|
||||
public PanTiltController(String portname, int baudrate, int cameraid){
|
||||
serialPort = SerialPort.getCommPort(portname);
|
||||
serialPort.setBaudRate(baudrate);
|
||||
this.cameraid = (byte)cameraid;
|
||||
SerialPort[] comports = SerialPort.getCommPorts();
|
||||
if (comports.length>0){
|
||||
for (SerialPort port : comports){
|
||||
Logger.info("Available Serial Port : {}", port.getSystemPortName());
|
||||
if (port.getSystemPortName().equals(portname)){
|
||||
Logger.info("Serial Port {} found", portname);
|
||||
serialPort = port;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (serialPort!=null){
|
||||
serialPort.setBaudRate(baudrate);
|
||||
if (serialPort.openPort()){
|
||||
Logger.info("Serial Port {} opened successfully at {}", portname, baudrate);
|
||||
} else {
|
||||
Logger.info("Failed to open Serial Port {} at {}", portname, baudrate);
|
||||
}
|
||||
} else Logger.info("Serial Port {} not found", portname);
|
||||
} else Logger.info("No Serial Port found");
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Close Pan Tilt Controller
|
||||
*/
|
||||
public void Close(){
|
||||
serialPort.closePort();
|
||||
if (serialPort!=null) serialPort.closePort();
|
||||
Logger.info("Serial Port closed");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,24 +7,59 @@ import org.tinylog.Logger;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static Other.SomeCodes.gson;
|
||||
|
||||
public class RtspGrabber {
|
||||
private final String rtspUrl;
|
||||
private FFmpegFrameGrabber grabber;
|
||||
private final AtomicBoolean isGrabbing = new AtomicBoolean(false);
|
||||
private @Getter Frame lastHQFrame = null;
|
||||
private @Getter Frame lastLQFrame = null;
|
||||
private @Getter String lastHQBase64 = null;
|
||||
private @Getter String lastLQBase64 = null;
|
||||
private Frame lastHQFrame = null;
|
||||
private Frame lastLQFrame = null;
|
||||
private String lastHQBase64 = null;
|
||||
private String lastLQBase64 = null;
|
||||
private @Getter int HQWidth = 0;
|
||||
private @Getter int HQHeight = 0;
|
||||
private @Getter int LQWidth = 0;
|
||||
private @Getter int LQHeight = 0;
|
||||
private GrabbingTask grabbingTask;
|
||||
|
||||
public RtspGrabber(String ip, String path) {
|
||||
this.rtspUrl = "rtsp://" + ip + path;
|
||||
Logger.info("RtspGrabber created with url: " + rtspUrl);
|
||||
}
|
||||
|
||||
private synchronized void setLastHQFrame(Frame frame){
|
||||
lastHQFrame = frame;
|
||||
}
|
||||
|
||||
public synchronized Frame getLastHQFrame(){
|
||||
return lastHQFrame;
|
||||
}
|
||||
|
||||
private synchronized void setLastLQFrame(Frame frame){
|
||||
lastLQFrame = frame;
|
||||
}
|
||||
|
||||
public synchronized Frame getLastLQFrame(){
|
||||
return lastLQFrame;
|
||||
}
|
||||
|
||||
private synchronized void setLastHQBase64(String base64){
|
||||
lastHQBase64 = base64;
|
||||
}
|
||||
|
||||
public synchronized String getLastHQBase64(){
|
||||
return lastHQBase64;
|
||||
}
|
||||
|
||||
private synchronized void setLastLQBase64(String base64){
|
||||
lastLQBase64 = base64;
|
||||
}
|
||||
|
||||
public synchronized String getLastLQBase64(){
|
||||
return lastLQBase64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start grabbing frames from rtsp
|
||||
* @param useTcp Use tcp instead of udp
|
||||
@@ -34,11 +69,12 @@ public class RtspGrabber {
|
||||
try{
|
||||
grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
|
||||
if (useTcp) grabber.setOption("rtsp_transport", "tcp");
|
||||
|
||||
grabber.setTimeout(2000);
|
||||
grabber.setImageWidth(width);
|
||||
grabber.setImageHeight(height);
|
||||
grabber.setPixelFormat(avutil.AV_PIX_FMT_BGR24);
|
||||
grabber.start();
|
||||
|
||||
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
|
||||
|
||||
|
||||
@@ -49,7 +85,7 @@ public class RtspGrabber {
|
||||
tt.setOnHQFrameUpdate(value -> {
|
||||
if (value!=null){
|
||||
if (value.imageWidth>0 && value.imageHeight>0){
|
||||
lastHQFrame = value;
|
||||
setLastHQFrame(value);
|
||||
HQWidth = value.imageWidth;
|
||||
HQHeight = value.imageHeight;
|
||||
}
|
||||
@@ -59,14 +95,15 @@ public class RtspGrabber {
|
||||
tt.setOnLQFrameUpdate(value -> {
|
||||
if (value!=null){
|
||||
if (value.imageWidth>0 && value.imageHeight>0){
|
||||
lastLQFrame = value;
|
||||
setLastLQFrame(value);
|
||||
LQWidth = value.imageWidth;
|
||||
LQHeight = value.imageHeight;
|
||||
}
|
||||
}
|
||||
});
|
||||
tt.setOnHQBase64Update(value -> lastHQBase64 = value);
|
||||
tt.setOnLQBase64Update(value -> lastLQBase64 = value);
|
||||
tt.setOnHQBase64Update(this::setLastHQBase64);
|
||||
tt.setOnLQBase64Update(this::setLastLQBase64);
|
||||
grabbingTask = tt;
|
||||
new Thread(tt).start();
|
||||
|
||||
} catch (Exception e){
|
||||
@@ -78,17 +115,28 @@ public class RtspGrabber {
|
||||
* Stop grabbing frames
|
||||
*/
|
||||
public void Stop(){
|
||||
isGrabbing.set(false);
|
||||
if (grabbingTask!=null){
|
||||
grabbingTask.Stop();
|
||||
}
|
||||
grabbingTask = null;
|
||||
if (grabber!=null) {
|
||||
try{
|
||||
isGrabbing.set(false);
|
||||
grabber.stop();
|
||||
grabber.releaseUnsafe();
|
||||
Logger.info("Grabber stopped");
|
||||
} catch (Exception e){
|
||||
Logger.error("Error stopping grabber: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
grabber = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String LQStreamingStatus(){
|
||||
return gson.toJson(new String[]{String.valueOf(LQWidth), String.valueOf(LQHeight) , String.valueOf(grabbingTask.getCaptureFPS())});
|
||||
}
|
||||
|
||||
public String HQStreamingStatus(){
|
||||
return gson.toJson(new String[]{String.valueOf(HQWidth), String.valueOf(HQHeight) , String.valueOf(grabbingTask.getCaptureFPS())});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package Other;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.bytedeco.javacpp.Loader;
|
||||
import org.bytedeco.javacv.Frame;
|
||||
import org.bytedeco.javacv.Java2DFrameConverter;
|
||||
@@ -42,6 +43,7 @@ public class SomeCodes {
|
||||
public static final boolean haveOpenCL = opencv_core.haveOpenCL();
|
||||
public static boolean useOpenCL;
|
||||
private static final Base64.Encoder base64encoder = java.util.Base64.getEncoder();
|
||||
public static final Gson gson = new Gson();
|
||||
|
||||
public static String[] GetAudioFiles(){
|
||||
try{
|
||||
@@ -49,6 +51,7 @@ public class SomeCodes {
|
||||
} catch (Exception e){
|
||||
Logger.error("Error getting audio files: "+e.getMessage());
|
||||
}
|
||||
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@@ -199,10 +202,15 @@ public class SomeCodes {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load properties file
|
||||
* @param filename properties file name
|
||||
* @return Properties object loaded, or empty new Properties object if error
|
||||
*/
|
||||
public static @NotNull Properties LoadProperties(String filename){
|
||||
try{
|
||||
InputStream is = new FileInputStream(filename);
|
||||
File ff = new File(currentDirectory, filename);
|
||||
InputStream is = new FileInputStream(ff);
|
||||
Properties prop = new Properties();
|
||||
prop.load(is);
|
||||
return prop;
|
||||
@@ -212,9 +220,16 @@ public class SomeCodes {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save properties file
|
||||
* @param prop Properties object to save
|
||||
* @param filename properties file name
|
||||
* @return true if success, false otherwise
|
||||
*/
|
||||
public static boolean SaveProperties(Properties prop, String filename){
|
||||
try{
|
||||
OutputStream os = new FileOutputStream(filename);
|
||||
File ff = new File(currentDirectory, filename);
|
||||
OutputStream os = new FileOutputStream(ff);
|
||||
prop.store(os, null);
|
||||
return true;
|
||||
} catch (Exception e){
|
||||
@@ -236,6 +251,7 @@ public class SomeCodes {
|
||||
UMat src = new UMat();
|
||||
source.copyTo(src);
|
||||
UMat dst = new UMat();
|
||||
|
||||
opencv_imgproc.resize(src, dst, sz);
|
||||
dst.copyTo(dest);
|
||||
} else {
|
||||
@@ -249,4 +265,19 @@ public class SomeCodes {
|
||||
Mat resized = ResizeMat(mat, width, height);
|
||||
return matConverter.convert(resized);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if an ip address is reachable
|
||||
* @param ipaddress ip address to check
|
||||
* @return true if valid and reachable, false otherwise
|
||||
*/
|
||||
public static boolean IpIsReachable(String ipaddress){
|
||||
try{
|
||||
InetAddress inet = InetAddress.getByName(ipaddress);
|
||||
return inet.isReachable(1000);
|
||||
} catch (Exception e){
|
||||
Logger.error("Error checking ip address: "+e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
8
src/main/java/SBC/CpuInfo.java
Normal file
8
src/main/java/SBC/CpuInfo.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package SBC;
|
||||
|
||||
public class CpuInfo {
|
||||
public int processorCount;
|
||||
public String revision;
|
||||
public String serial;
|
||||
public String model;
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import org.tinylog.Logger;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class GPIO {
|
||||
|
||||
private static final Path gpioPath = Path.of("/sys/class/gpio");
|
||||
@@ -14,10 +13,8 @@ public class GPIO {
|
||||
private static final Path gpioUnexportPath = Path.of("/sys/class/gpio/unexport");
|
||||
|
||||
|
||||
public static boolean IsRaspberry64(){
|
||||
public static boolean HaveGPIO(){
|
||||
if (Platform.isLinux()){
|
||||
if (Platform.isARM()){
|
||||
if (Platform.is64Bit()){
|
||||
if (gpioPath.toFile().isDirectory()){
|
||||
if (gpioExportPath.toFile().isFile()){
|
||||
if (gpioUnexportPath.toFile().isFile()){
|
||||
@@ -25,8 +22,6 @@ public class GPIO {
|
||||
} else Logger.error("GPIO unexport path is not found");
|
||||
} else Logger.error("GPIO export path is not found");
|
||||
} else Logger.error("GPIO path is not found");
|
||||
} else Logger.info("Device is not 64 bit");
|
||||
} else Logger.info("Device is not ARM");
|
||||
} else Logger.info("OS is not Linux");
|
||||
return false;
|
||||
}
|
||||
|
||||
84
src/main/java/SBC/NetworkTransmitReceiveInfo.java
Normal file
84
src/main/java/SBC/NetworkTransmitReceiveInfo.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package SBC;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static Other.SomeCodes.ValidString;
|
||||
|
||||
public class NetworkTransmitReceiveInfo {
|
||||
public String name;
|
||||
public long bytesReceived;
|
||||
public long packetsReceived;
|
||||
public long errorsReceived;
|
||||
public long droppedReceived;
|
||||
public long fifoReceived;
|
||||
public long frameReceived;
|
||||
public long compressedReceived;
|
||||
public long multicastReceived;
|
||||
public long bytesTransmitted;
|
||||
public long packetsTransmitted;
|
||||
public long errorsTransmitted;
|
||||
public long droppedTransmitted;
|
||||
public long fifoTransmitted;
|
||||
public long collsTransmitted;
|
||||
public long carrierTransmitted;
|
||||
public long compressedTransmitted;
|
||||
public long timetick;
|
||||
|
||||
/**
|
||||
* Calculate the download speed
|
||||
* @param prev Previous NetworkTransmitReceiveInfo
|
||||
* @param unit Speed unit (KB, MB, GB)
|
||||
* @return Download speed in {unit}/second
|
||||
*/
|
||||
public double RxSpeed(NetworkTransmitReceiveInfo prev, String unit){
|
||||
if (prev!=null){
|
||||
if (Objects.equals(prev.name, name)){
|
||||
long timeDiff = timetick - prev.timetick;
|
||||
if (timeDiff>0){
|
||||
long bytesDiff = bytesReceived - prev.bytesReceived;
|
||||
if (ValidString(unit)) unit = unit.toUpperCase();
|
||||
Double speed = ConvertToUnit(unit, timeDiff, bytesDiff);
|
||||
if (speed != null) return speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Double ConvertToUnit(String unit, long timeDiff, long bytesDiff) {
|
||||
if (bytesDiff>0){
|
||||
double speed = ((double) bytesDiff / timeDiff) * 1000;
|
||||
return switch (unit) {
|
||||
case "KB" -> speed / 1024;
|
||||
case "MB" -> speed / 1024 / 1024;
|
||||
case "GB" -> speed / 1024 / 1024 / 1024;
|
||||
default -> speed;
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the upload speed
|
||||
* @param prev Previous NetworkTransmitReceiveInfo
|
||||
* @param unit Speed unit (KB, MB, GB)
|
||||
* @return Upload speed in {unit}/second
|
||||
*/
|
||||
public double TxSpeed(NetworkTransmitReceiveInfo prev, String unit){
|
||||
if (prev!=null){
|
||||
if (Objects.equals(prev.name, name)){
|
||||
long timeDiff = timetick - prev.timetick;
|
||||
if (timeDiff>0){
|
||||
long bytesDiff = bytesTransmitted - prev.bytesTransmitted;
|
||||
if (ValidString(unit)) unit = unit.toUpperCase();
|
||||
Double speed = ConvertToUnit(unit, timeDiff, bytesDiff);
|
||||
if (speed != null) return speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
45
src/main/java/SBC/ProcessorStatus.java
Normal file
45
src/main/java/SBC/ProcessorStatus.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package SBC;
|
||||
|
||||
public class ProcessorStatus {
|
||||
public String name;
|
||||
public int user;
|
||||
public int nice;
|
||||
public int system;
|
||||
public int idle;
|
||||
public int iowait;
|
||||
public int irq;
|
||||
public int softirq;
|
||||
public int steal;
|
||||
public int guest;
|
||||
public int guest_nice;
|
||||
|
||||
/**
|
||||
* Calculate total CPU time
|
||||
* @return Total CPU time
|
||||
*/
|
||||
public int total_time(){
|
||||
return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate idle CPU time
|
||||
* @return Idle CPU time
|
||||
*/
|
||||
public int idle_time(){
|
||||
return idle + iowait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate CPU usage percentage
|
||||
* @param prev Previous CPU information
|
||||
* @return CPU usage percentage 0 - 100
|
||||
*/
|
||||
public int cpu_usage(ProcessorStatus prev){
|
||||
if (prev!=null){
|
||||
int total_diff = total_time() - prev.total_time();
|
||||
int idle_diff = idle_time() - prev.idle_time();
|
||||
return (int)(100.0 * (total_diff - idle_diff) / total_diff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
12
src/main/java/SBC/RamInformation.java
Normal file
12
src/main/java/SBC/RamInformation.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package SBC;
|
||||
|
||||
public class RamInformation {
|
||||
public int totalKB;
|
||||
public int usedKB;
|
||||
public int availableKB;
|
||||
public int swapTotalKB;
|
||||
public int swapFreeKB;
|
||||
public double RamUsagePercentage(){
|
||||
return (double) usedKB / totalKB * 100;
|
||||
}
|
||||
}
|
||||
179
src/main/java/SBC/SystemInformation.java
Normal file
179
src/main/java/SBC/SystemInformation.java
Normal file
@@ -0,0 +1,179 @@
|
||||
package SBC;
|
||||
|
||||
import com.sun.jna.Platform;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SystemInformation {
|
||||
|
||||
|
||||
|
||||
public static int getCPUTemperature() {
|
||||
if (Platform.isLinux()){
|
||||
File ff = new File("/sys/class/thermal/thermal_zone0/temp");
|
||||
if (ff.isFile() && ff.canRead()){
|
||||
try{
|
||||
String value = Files.readString(ff.toPath()).trim();
|
||||
return Integer.parseInt(value) / 1000;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static NetworkTransmitReceiveInfo[] getNetworkTransmitReceiveInfo(){
|
||||
if (Platform.isLinux()){
|
||||
File ff = new File("/proc/net/dev");
|
||||
if (ff.isFile() && ff.canRead()){
|
||||
List<NetworkTransmitReceiveInfo> result = new ArrayList<>();
|
||||
final Pattern pattern = Pattern.compile("\\s+(.*):\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
|
||||
try{
|
||||
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||
for (String line : lines){
|
||||
Matcher m = pattern.matcher(line);
|
||||
if (m.find()){
|
||||
NetworkTransmitReceiveInfo info = new NetworkTransmitReceiveInfo();
|
||||
info.name = m.group(1).trim();
|
||||
info.bytesReceived = Long.parseLong(m.group(2));
|
||||
info.packetsReceived = Long.parseLong(m.group(3));
|
||||
info.errorsReceived = Long.parseLong(m.group(4));
|
||||
info.droppedReceived = Long.parseLong(m.group(5));
|
||||
info.fifoReceived = Long.parseLong(m.group(6));
|
||||
info.frameReceived = Long.parseLong(m.group(7));
|
||||
info.compressedReceived = Long.parseLong(m.group(8));
|
||||
info.multicastReceived = Long.parseLong(m.group(9));
|
||||
info.bytesTransmitted = Long.parseLong(m.group(10));
|
||||
info.packetsTransmitted = Long.parseLong(m.group(11));
|
||||
info.errorsTransmitted = Long.parseLong(m.group(12));
|
||||
info.droppedTransmitted = Long.parseLong(m.group(13));
|
||||
info.fifoTransmitted = Long.parseLong(m.group(14));
|
||||
info.collsTransmitted = Long.parseLong(m.group(15));
|
||||
info.carrierTransmitted = Long.parseLong(m.group(16));
|
||||
info.compressedTransmitted = Long.parseLong(m.group(17));
|
||||
info.timetick = System.currentTimeMillis();
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
return result.toArray(new NetworkTransmitReceiveInfo[0]);
|
||||
}
|
||||
}
|
||||
return new NetworkTransmitReceiveInfo[0];
|
||||
}
|
||||
|
||||
public static CpuInfo getCPUInfo(){
|
||||
CpuInfo result = new CpuInfo();
|
||||
if (Platform.isLinux()){
|
||||
File ff = new File("/proc/cpuinfo");
|
||||
if (ff.isFile() && ff.canRead()){
|
||||
final Pattern pattern = Pattern.compile( "\\s*(.*):\\s*(.*)");
|
||||
try{
|
||||
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||
for (String line : lines){
|
||||
Matcher m = pattern.matcher(line);
|
||||
if (m.find()){
|
||||
String key = m.group(1).trim();
|
||||
String value = m.group(2).trim();
|
||||
switch (key){
|
||||
case "processor":
|
||||
result.processorCount++;
|
||||
break;
|
||||
case "Revision":
|
||||
result.revision = value;
|
||||
break;
|
||||
case "Serial":
|
||||
result.serial = value;
|
||||
break;
|
||||
case "Model":
|
||||
result.model = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ProcessorStatus[] getProcStat(){
|
||||
if (Platform.isLinux()){
|
||||
File ff = new File("/proc/stat");
|
||||
if (ff.isFile() && ff.canRead()){
|
||||
final Pattern pattern = Pattern.compile( "(cpu\\d?)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
|
||||
List<ProcessorStatus> result = new ArrayList<>();
|
||||
try{
|
||||
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||
for (String line : lines){
|
||||
Matcher m = pattern.matcher(line);
|
||||
if (m.find()){
|
||||
ProcessorStatus info = new ProcessorStatus();
|
||||
info.name = m.group(1).trim();
|
||||
info.user = Integer.parseInt(m.group(2));
|
||||
info.nice = Integer.parseInt(m.group(3));
|
||||
info.system = Integer.parseInt(m.group(4));
|
||||
info.idle = Integer.parseInt(m.group(5));
|
||||
info.iowait = Integer.parseInt(m.group(6));
|
||||
info.irq = Integer.parseInt(m.group(7));
|
||||
info.softirq = Integer.parseInt(m.group(8));
|
||||
info.steal = Integer.parseInt(m.group(9));
|
||||
info.guest = Integer.parseInt(m.group(10));
|
||||
info.guest_nice = Integer.parseInt(m.group(11));
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
return result.toArray(new ProcessorStatus[0]);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ProcessorStatus[0];
|
||||
}
|
||||
|
||||
public static RamInformation getRAMInformation(){
|
||||
|
||||
RamInformation result = new RamInformation();
|
||||
if (Platform.isLinux()){
|
||||
File ff = new File("/proc/meminfo");
|
||||
if (ff.isFile() && ff.canRead()){
|
||||
final Pattern pattern = Pattern.compile("(.*):\\s+(\\d+).kB");
|
||||
try{
|
||||
String[] lines = Files.readString(ff.toPath()).split("\n");
|
||||
for (String line : lines) {
|
||||
Matcher m = pattern.matcher(line);
|
||||
if (m.find()){
|
||||
String key = m.group(1);
|
||||
int value = Integer.parseInt(m.group(2));
|
||||
switch (key){
|
||||
case "MemTotal":
|
||||
result.totalKB = value;
|
||||
break;
|
||||
case "MemAvailable":
|
||||
result.availableKB = value;
|
||||
break;
|
||||
case "SwapTotal":
|
||||
result.swapTotalKB = value;
|
||||
break;
|
||||
case "SwapFree":
|
||||
result.swapFreeKB = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
result.usedKB = result.totalKB - result.availableKB;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
9
src/main/java/Web/AudioFilesInfo.java
Normal file
9
src/main/java/Web/AudioFilesInfo.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package Web;
|
||||
|
||||
public class AudioFilesInfo {
|
||||
public String preset1;
|
||||
public String preset2;
|
||||
public String preset3;
|
||||
public String preset4;
|
||||
public String preset5;
|
||||
}
|
||||
@@ -3,12 +3,14 @@ package Web;
|
||||
import Other.SomeCodes;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.UploadedFile;
|
||||
import io.javalin.util.FileUtil;
|
||||
import io.javalin.util.JavalinException;
|
||||
import io.javalin.websocket.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@@ -20,20 +22,24 @@ import static io.javalin.apibuilder.ApiBuilder.*;
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public class WebServer {
|
||||
private @Getter @Setter String webusername;
|
||||
private @Getter @Setter String webpassword;
|
||||
private final Javalin app;
|
||||
private final Set<WsContext> connectedWebsocketClients = ConcurrentHashMap.newKeySet();
|
||||
public WebServer(WebsocketEvent event, String webusername, String webpassword){
|
||||
this.webusername = webusername;
|
||||
this.webpassword = webpassword;
|
||||
app = Javalin.create(config -> {
|
||||
config.staticFiles.add("/html");
|
||||
config.router.apiBuilder(()-> path("setting", () ->{
|
||||
get(ctx -> ctx.json(SettingInfo.getInstance()));
|
||||
path("audiofile",()-> post(ctx -> {
|
||||
Logger.info("api /setting/audiofile");
|
||||
String audiofile1 = ctx.formParam("1");
|
||||
String audiofile2 = ctx.formParam("2");
|
||||
String audiofile3 = ctx.formParam("3");
|
||||
String audiofile4 = ctx.formParam("4");
|
||||
String audiofile5 = ctx.formParam("5");
|
||||
String audiofile1 = ctx.formParam("preset1");
|
||||
String audiofile2 = ctx.formParam("preset2");
|
||||
String audiofile3 = ctx.formParam("preset3");
|
||||
String audiofile4 = ctx.formParam("preset4");
|
||||
String audiofile5 = ctx.formParam("preset5");
|
||||
Logger.info("audiofile1: {}", audiofile1);
|
||||
Logger.info("audiofile2: {}", audiofile2);
|
||||
Logger.info("audiofile3: {}", audiofile3);
|
||||
@@ -41,41 +47,59 @@ public class WebServer {
|
||||
Logger.info("audiofile5: {}", audiofile5);
|
||||
|
||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||
prop.setProperty("audiofile1", audiofile1!=null?audiofile1:"");
|
||||
prop.setProperty("audiofile2", audiofile2!=null?audiofile2:"");
|
||||
prop.setProperty("audiofile3", audiofile3!=null?audiofile3:"");
|
||||
prop.setProperty("audiofile4", audiofile4!=null?audiofile4:"");
|
||||
prop.setProperty("audiofile5", audiofile5!=null?audiofile5:"");
|
||||
prop.setProperty("AudioFile01", audiofile1!=null?audiofile1:"");
|
||||
prop.setProperty("AudioFile02", audiofile2!=null?audiofile2:"");
|
||||
prop.setProperty("AudioFile03", audiofile3!=null?audiofile3:"");
|
||||
prop.setProperty("AudioFile04", audiofile4!=null?audiofile4:"");
|
||||
prop.setProperty("AudioFile05", audiofile5!=null?audiofile5:"");
|
||||
if (SaveProperties(prop, "config.properties")){
|
||||
Logger.info("audiofile saved");
|
||||
ctx.status(200);
|
||||
} else {
|
||||
Logger.error("Failed to save audiofile");
|
||||
ctx.status(400);
|
||||
ctx.result("Failed to save audiofile");
|
||||
}
|
||||
}));
|
||||
path("uploadaudiofile", ()-> post(ctx -> {
|
||||
UploadedFile file = ctx.uploadedFile("file");
|
||||
if (file!=null){
|
||||
try {
|
||||
Path targetsave = audioPath.resolve(file.filename());
|
||||
Files.copy(file.content(), targetsave);
|
||||
Logger.info("Uploaded file: {}, size: {} saved at {}", file.filename(),file.size(), targetsave);
|
||||
} catch (Exception e){
|
||||
Logger.error("Failed to save uploaded file: {}, Message: {}", file.filename(), e.getMessage());
|
||||
}
|
||||
List<UploadedFile> uploadedFileList = ctx.uploadedFiles();
|
||||
int size = uploadedFileList.size();
|
||||
if (size>0){
|
||||
uploadedFileList.forEach(ff ->{
|
||||
String targetsave = audioPath.resolve(ff.filename()).toString();
|
||||
FileUtil.streamToFile(ff.content(), targetsave);
|
||||
Logger.info("Uploaded file: {}", targetsave);
|
||||
});
|
||||
ctx.status(200);
|
||||
ctx.result("UploadedFiles: "+size);
|
||||
} else {
|
||||
ctx.status(400);
|
||||
ctx.result("No file uploaded");
|
||||
}
|
||||
|
||||
|
||||
}));
|
||||
path("weblogin", ()-> post(ctx -> {
|
||||
String username = ctx.formParam("username");
|
||||
String password = ctx.formParam("password");
|
||||
Logger.info("api /setting/weblogin");
|
||||
Logger.info("username: {}", username);
|
||||
Logger.info("password: {}", password);
|
||||
|
||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||
prop.setProperty("WebUsername", ValidString(username)?username:"admin");
|
||||
prop.setProperty("WebPassword", ValidString(password)?password:"bandara");
|
||||
if (SaveProperties(prop, "config.properties")){
|
||||
ctx.status(200);
|
||||
Logger.info("weblogin saved");
|
||||
|
||||
//ctx.status(200);
|
||||
this.webusername = username;
|
||||
this.webpassword = password;
|
||||
ctx.redirect("/logout");
|
||||
} else {
|
||||
Logger.error("Failed to save weblogin");
|
||||
ctx.status(400);
|
||||
ctx.result("Failed to save weblogin");
|
||||
}
|
||||
}));
|
||||
path("camera",()-> post(ctx -> {
|
||||
@@ -83,6 +107,11 @@ public class WebServer {
|
||||
String camera_port = ctx.formParam("port");
|
||||
String camera_username = ctx.formParam("username");
|
||||
String camera_password = ctx.formParam("password");
|
||||
Logger.info("api /setting/camera");
|
||||
Logger.info("camera_ip: {}", camera_ip);
|
||||
Logger.info("camera_port: {}", camera_port);
|
||||
Logger.info("camera_username: {}", camera_username);
|
||||
Logger.info("camera_password: {}", camera_password);
|
||||
|
||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||
prop.setProperty("Camera_ip", ValidString(camera_ip)?camera_ip:"192.168.0.4");
|
||||
@@ -90,9 +119,13 @@ public class WebServer {
|
||||
prop.setProperty("Camera_user", ValidString(camera_username)?camera_username:"root");
|
||||
prop.setProperty("Camera_password", ValidString(camera_password)?camera_password:"password");
|
||||
if (SaveProperties(prop, "config.properties")){
|
||||
Logger.info("IP camera setting saved");
|
||||
ctx.status(200);
|
||||
if (event!=null) event.NewCameraConfiguration();
|
||||
} else {
|
||||
Logger.error("Failed to save IP camera setting");
|
||||
ctx.status(400);
|
||||
ctx.result("Failed to save IP camera setting");
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -103,7 +136,7 @@ public class WebServer {
|
||||
if (ctx.sessionAttribute("username")==null) {
|
||||
// belum login
|
||||
ctx.redirect("/login.html");
|
||||
} else if (Objects.equals(ctx.sessionAttribute("username"), webusername)){
|
||||
} else if (Objects.equals(ctx.sessionAttribute("username"), this.webusername)){
|
||||
// sudah login
|
||||
ctx.redirect("/index.html");
|
||||
} else {
|
||||
@@ -127,11 +160,12 @@ public class WebServer {
|
||||
app.post("/login", ctx ->{
|
||||
String username = ctx.formParam("username");
|
||||
String password = ctx.formParam("password");
|
||||
if (Objects.equals(username, webusername) && Objects.equals(password, webpassword)){
|
||||
if (Objects.equals(username, this.webusername) && Objects.equals(password, this.webpassword)){
|
||||
ctx.sessionAttribute("username", username);
|
||||
ctx.redirect("/index.html");
|
||||
} else {
|
||||
ctx.redirect("/login.html?error=Invalid username or password");
|
||||
ctx.status(400);
|
||||
ctx.redirect("/login.html");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -151,9 +185,12 @@ public class WebServer {
|
||||
if (event!=null) {
|
||||
WebsocketReply reply = event.onWebsocketCommand(command);
|
||||
if (reply!=null) ctx.sendAsClass(reply, WebsocketReply.class);
|
||||
//if (reply!=null) SendtoAll(reply);
|
||||
}
|
||||
} catch (Exception e){
|
||||
Logger.error("Failed to parse WebSocketCommand message: {}", e.getMessage());
|
||||
ctx.closeSession();
|
||||
connectedWebsocketClients.remove(ctx);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -196,13 +233,13 @@ public class WebServer {
|
||||
}
|
||||
|
||||
WsConnectHandler connectws = ws ->{
|
||||
Logger.info("WebSocket connected from {}", ws.host());
|
||||
Logger.info("WebSocket connected from {}", ws.sessionId());
|
||||
//ws.headerMap().forEach((key, value) -> Logger.info("HeaderMap {}: {}", key, value));
|
||||
connectedWebsocketClients.add(ws);
|
||||
};
|
||||
|
||||
WsCloseHandler closews = ws ->{
|
||||
Logger.info("WebSocket closed from {}, code {}, reason {}", ws.host(), ws.status(), ws.reason());
|
||||
Logger.info("WebSocket closed from {}, code {}, reason {}", ws.sessionId(), ws.status(), ws.reason());
|
||||
connectedWebsocketClients.remove(ws);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,4 +3,5 @@ package Web;
|
||||
public interface WebsocketEvent {
|
||||
String onMessage(String message);
|
||||
WebsocketReply onWebsocketCommand(WebsocketCommand command);
|
||||
void NewCameraConfiguration();
|
||||
}
|
||||
|
||||
@@ -2,22 +2,23 @@ package id.co.gtc;
|
||||
|
||||
import Audio.AudioFileProperties;
|
||||
import Audio.AudioPlayer;
|
||||
import Audio.Bass;
|
||||
import Audio.PlaybackEvent;
|
||||
import Camera.PanTiltController;
|
||||
import Camera.RtspGrabber;
|
||||
import Camera.VapixProtocol;
|
||||
import Other.SomeCodes;
|
||||
import Web.WebServer;
|
||||
import Web.WebsocketCommand;
|
||||
import Web.WebsocketEvent;
|
||||
import Web.WebsocketReply;
|
||||
import SBC.ProcessorStatus;
|
||||
import SBC.RamInformation;
|
||||
import SBC.SystemInformation;
|
||||
import Web.*;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.bytedeco.opencv.global.opencv_core;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
|
||||
import static Other.SomeCodes.*;
|
||||
|
||||
@@ -28,6 +29,11 @@ public class Main {
|
||||
private static PanTiltController panTiltController;
|
||||
private static AudioFileProperties audioFileProperties;
|
||||
private static VapixProtocol vapixProtocol;
|
||||
private static Timer timer;
|
||||
private static int cpuTemperature;
|
||||
private static RamInformation ramInformation;
|
||||
private static ProcessorStatus[] previousCpuInfo;
|
||||
private static final Map<String, Integer> cpuUsage = new HashMap<>();
|
||||
|
||||
// Application start from here
|
||||
public static void main(String[] args) {
|
||||
@@ -37,8 +43,11 @@ public class Main {
|
||||
if (rtspGrabber!=null) rtspGrabber.Stop();
|
||||
if (panTiltController!=null) panTiltController.Close();
|
||||
if (vapixProtocol!=null) vapixProtocol.Close();
|
||||
if (timer!=null) timer.cancel();
|
||||
}));
|
||||
|
||||
init_system_monitoring();
|
||||
|
||||
init_properties();
|
||||
init_audiofiles();
|
||||
|
||||
@@ -49,6 +58,29 @@ public class Main {
|
||||
init_Vapix();
|
||||
}
|
||||
|
||||
private static void init_system_monitoring(){
|
||||
TimerTask tt = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
cpuTemperature = SystemInformation.getCPUTemperature();
|
||||
ramInformation = SystemInformation.getRAMInformation();
|
||||
ProcessorStatus[] cpuinfo = SystemInformation.getProcStat();
|
||||
if (cpuinfo.length>0){
|
||||
if (previousCpuInfo==null || !Objects.equals(previousCpuInfo.length, cpuinfo.length)){
|
||||
previousCpuInfo = cpuinfo;
|
||||
} else {
|
||||
for(int ii=0;ii<previousCpuInfo.length;ii++){
|
||||
cpuUsage.put(cpuinfo[ii].name, cpuinfo[ii].cpu_usage(previousCpuInfo[ii]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
timer = new Timer();
|
||||
timer.scheduleAtFixedRate(tt, 1000, 5000);
|
||||
|
||||
}
|
||||
|
||||
private static void init_properties(){
|
||||
if (ExtractResource("/tinylog.properties", currentDirectory)==null) Logger.error("Failed to extract tinylog.properties");
|
||||
if (ExtractResource("/config.properties", currentDirectory)==null) Logger.error("Failed to extract config.properties");
|
||||
@@ -73,9 +105,11 @@ public class Main {
|
||||
String username = config.getProperty("Camera_user");
|
||||
String password = config.getProperty("Camera_password");
|
||||
if (ValidString(ip)){
|
||||
if (ValidInteger(port)){
|
||||
if (ValidPortNumber(port)){
|
||||
if (ValidString(username)){
|
||||
if (ValidString(password)){
|
||||
if (IpIsReachable(ip)){
|
||||
Logger.info("Camera IP is reachable");
|
||||
vapixProtocol = new VapixProtocol(ip, Integer.parseInt(port), username, password);
|
||||
Logger.info("Camera Product Number: "+vapixProtocol.GetProductNumber());
|
||||
Logger.info("Camera Serial Number: "+vapixProtocol.GetSerialNumber());
|
||||
@@ -84,10 +118,11 @@ public class Main {
|
||||
} else Logger.error("PTZ Disabled");
|
||||
Logger.info("Max Zoom: "+vapixProtocol.GetPTZMaxZoom());
|
||||
Logger.info("Min Zoom: "+vapixProtocol.GetPTZMinZoom());
|
||||
} else Logger.error("Invalid Camera Password");
|
||||
} else Logger.error("Invalid Camera Username");
|
||||
} else Logger.error("Invalid Camera Port");
|
||||
} else Logger.error("Invalid Camera IP");
|
||||
} else Logger.error("Camera IP is not reachable");
|
||||
} else Logger.error("Camera Password is not valid string");
|
||||
} else Logger.error("Camera Username is not valid string");
|
||||
} else Logger.error("Camera Port is not valid");
|
||||
} else Logger.error( "Camera IP is not valid string");
|
||||
}
|
||||
|
||||
private static void init_pantiltcontroller() {
|
||||
@@ -112,22 +147,32 @@ public class Main {
|
||||
Properties config = SomeCodes.LoadProperties("config.properties");
|
||||
String targetip = config.getProperty("Camera_ip");
|
||||
String rtsppath = config.getProperty("Camera_Rtsp_path");
|
||||
rtspGrabber = null;
|
||||
if (ValidString(targetip)){
|
||||
if (ValidString(rtsppath)){
|
||||
if (IpIsReachable(targetip)){
|
||||
Logger.info("Camera IP is reachable");
|
||||
rtspGrabber = new RtspGrabber(targetip, rtsppath);
|
||||
|
||||
|
||||
rtspGrabber.Start(true, 1920, 1080);
|
||||
} else Logger.error("Invalid Camera Path");
|
||||
} else Logger.error("Invalid Camera IP");
|
||||
} else Logger.error("Camera IP is not reachable");
|
||||
} else Logger.error("Camera Path is not valid string");
|
||||
} else Logger.error("Camera IP is not valid string");
|
||||
}
|
||||
|
||||
private static void init_audio() {
|
||||
audioPlayer = new AudioPlayer();
|
||||
audioPlayer.DetectOutputDevices();
|
||||
audioPlayer.OpenDevice(1,48000);
|
||||
int devid = audioPlayer.FindDeviceIDWithName("USB");
|
||||
if (devid<1) devid = audioPlayer.FindDeviceIDWithName("Speakers");
|
||||
|
||||
if (devid>0){
|
||||
Bass.BASS_DEVICEINFO info = audioPlayer.GetDeviceInfo(devid);
|
||||
if (audioPlayer.OpenDevice(devid,48000)){
|
||||
audioPlayer.setMasterVolume(100);
|
||||
audioPlayer.setPlaybackvolume(100);
|
||||
Logger.info("Audio Device ID={} opened : {}", devid, info.name);
|
||||
} else Logger.error("Failed to open Audio Device ID={}", devid);
|
||||
} else Logger.error("USB Audio Device not found");
|
||||
}
|
||||
|
||||
static PlaybackEvent pe = new PlaybackEvent() {
|
||||
@@ -217,6 +262,7 @@ public class Main {
|
||||
audioFileProperties = afp;
|
||||
audioPlayer.PlayAudioFile(afp, true, pe);
|
||||
return new WebsocketReply("PLAY AUDIO", afp.filename);
|
||||
|
||||
} else return new WebsocketReply("PLAY AUDIO", "Failed to open audio file "+filename);
|
||||
} else return new WebsocketReply("PLAY AUDIO", "Audio file not found : "+filename);
|
||||
} else return new WebsocketReply("PLAY AUDIO", String.format("AudioFile with ID %02d not found", id));
|
||||
@@ -252,20 +298,64 @@ public class Main {
|
||||
case "GET BASE64":
|
||||
if (rtspGrabber!=null){
|
||||
if (Objects.equals(command.data,"HQ"))
|
||||
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), String.format("Streaming at %dx%d", rtspGrabber.getHQWidth(), rtspGrabber.getHQHeight()));
|
||||
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastHQBase64(), rtspGrabber.HQStreamingStatus());
|
||||
else
|
||||
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), String.format("Streaming at %dx%d", rtspGrabber.getLQWidth(), rtspGrabber.getLQHeight()));
|
||||
return new WebsocketReply("GET BASE64", "data:image/jpeg;base64,"+ rtspGrabber.getLastLQBase64(), rtspGrabber.LQStreamingStatus());
|
||||
} else return new WebsocketReply("GET BASE64", "RTSP Grabber not initialized");
|
||||
case "GET RESOLUTION":
|
||||
if (vapixProtocol!=null){
|
||||
int[] res = vapixProtocol.GetCurrentResolution(1);
|
||||
return new WebsocketReply("GET RESOLUTION", String.format("%dx%d", res[0], res[1]));
|
||||
} else return new WebsocketReply("GET RESOLUTION", "VapixProtocol not initialized");
|
||||
|
||||
case "GET AUDIOFILES":
|
||||
AudioFilesInfo afi = new AudioFilesInfo();
|
||||
afi.preset1 = GetConfigAudioFile(1);
|
||||
afi.preset2 = GetConfigAudioFile(2);
|
||||
afi.preset3 = GetConfigAudioFile(3);
|
||||
afi.preset4 = GetConfigAudioFile(4);
|
||||
afi.preset5 = GetConfigAudioFile(5);
|
||||
return new WebsocketReply("GET AUDIOFILES", gson.toJson(afi));
|
||||
case "GET SYSTEM INFO":
|
||||
JsonObject data = new JsonObject();
|
||||
data.addProperty("cpu_temperature", String.valueOf(cpuTemperature));
|
||||
if (ramInformation!=null) {
|
||||
data.addProperty("ram_usage", String.format("%.1f", ramInformation.RamUsagePercentage()));
|
||||
}
|
||||
if (!cpuUsage.isEmpty()) {
|
||||
for(String key : cpuUsage.keySet()){
|
||||
data.addProperty(key, String.valueOf(cpuUsage.get(key)));
|
||||
}
|
||||
}
|
||||
return new WebsocketReply("GET SYSTEM INFO", data.toString());
|
||||
default:
|
||||
return new WebsocketReply("UNKNOWN COMMAND", command.command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void NewCameraConfiguration() {
|
||||
Logger.info("New Camera Configuration detected");
|
||||
Properties prop = SomeCodes.LoadProperties("config.properties");
|
||||
String camera_ip = prop.getProperty("Camera_ip");
|
||||
String camera_port = prop.getProperty("Camera_port");
|
||||
String camera_user = prop.getProperty("Camera_user");
|
||||
String camera_password = prop.getProperty("Camera_password");
|
||||
String camera_rtsp_path = prop.getProperty("Camera_Rtsp_path");
|
||||
Logger.info("Camera Ip: "+camera_ip);
|
||||
Logger.info("Camera Port: "+camera_port);
|
||||
Logger.info("Camera User: "+camera_user);
|
||||
Logger.info("Camera Password: "+camera_password);
|
||||
Logger.info("Camera Rtsp Path: "+camera_rtsp_path);
|
||||
|
||||
if (rtspGrabber!=null) rtspGrabber.Stop();
|
||||
init_rtspgrabber();
|
||||
Logger.info("RtspGrabber recreated");
|
||||
|
||||
if (vapixProtocol!=null) vapixProtocol.Close();
|
||||
init_Vapix();
|
||||
Logger.info("VapixProtocol recreated");
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
private static void init_webserver() {
|
||||
|
||||
Reference in New Issue
Block a user