Commit 12/08/2025
This commit is contained in:
109
html/webpage/assets/js/hardwarestatus.js
Normal file
109
html/webpage/assets/js/hardwarestatus.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
$(document).ready(function() {
|
||||||
|
const path = window.location.pathname;
|
||||||
|
const ws = new WebSocket('ws://' + window.location.host + path + '/ws');
|
||||||
|
|
||||||
|
ws.onopen = function() {
|
||||||
|
//console.log('WebSocket connection opened');
|
||||||
|
$('#indicatorDisconnected').addClass('visually-hidden');
|
||||||
|
$('#indicatorConnected').removeClass('visually-hidden');
|
||||||
|
setInterval(function() {
|
||||||
|
sendCommand({ command: "getCPUStatus" });
|
||||||
|
sendCommand({ command: "getMemoryStatus" });
|
||||||
|
sendCommand({ command: "getDiskStatus" });
|
||||||
|
sendCommand({ command: "getEthernetStatus" });
|
||||||
|
sendCommand({ command: "getModemStatus" });
|
||||||
|
sendCommand({ command: "getTunnelStatus" });
|
||||||
|
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = function(event) {
|
||||||
|
//console.log('WebSocket message received:', event.data);
|
||||||
|
let msg = {};
|
||||||
|
try {
|
||||||
|
msg = JSON.parse(event.data);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Invalid JSON:', event.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.reply && msg.reply.length>0 && msg.data && msg.data.length > 0) {
|
||||||
|
switch (msg.reply) {
|
||||||
|
case "getCPUStatus":
|
||||||
|
const cpuData = JSON.parse(msg.data);
|
||||||
|
//console.log('CPU Status Data:', cpuData);
|
||||||
|
$('#cpuUsage').text(cpuData.average ? cpuData.average + '%' : 'N/A');
|
||||||
|
$('#core0Usage').text(cpuData.core0 ? cpuData.core0 + '%' : 'N/A');
|
||||||
|
$('#core1Usage').text(cpuData.core1 ? cpuData.core1 + '%' : 'N/A');
|
||||||
|
$('#core2Usage').text(cpuData.core2 ? cpuData.core2 + '%' : 'N/A');
|
||||||
|
$('#core3Usage').text(cpuData.core3 ? cpuData.core3 + '%' : 'N/A');
|
||||||
|
$('#cpuTemperature').text(cpuData.temperature ? cpuData.temperature + '°C' : 'N/A');
|
||||||
|
break;
|
||||||
|
case "getMemoryStatus":
|
||||||
|
const memoryData = JSON.parse(msg.data);
|
||||||
|
//console.log('Memory Status Data:', memoryData);
|
||||||
|
$('#ramTotal').text(memoryData.total ? memoryData.total : 'N/A');
|
||||||
|
$('#ramUsed').text(memoryData.used ? memoryData.used : 'N/A');
|
||||||
|
$('#ramFree').text(memoryData.free ? memoryData.free : 'N/A');
|
||||||
|
$('#ramFreePercent').text(memoryData.freePercent ? memoryData.freePercent + '%' : 'N/A');
|
||||||
|
break;
|
||||||
|
case "getDiskStatus":
|
||||||
|
const diskData = JSON.parse(msg.data);
|
||||||
|
//console.log('Disk Status Data:', diskData);
|
||||||
|
$('#diskTotal').text(diskData.total ? diskData.total : 'N/A');
|
||||||
|
$('#diskUsed').text(diskData.used ? diskData.used : 'N/A');
|
||||||
|
$('#diskFree').text(diskData.free ? diskData.free : 'N/A');
|
||||||
|
$('#diskFreePercent').text(diskData.freePercent ? diskData.freePercent + '%' : 'N/A');
|
||||||
|
break;
|
||||||
|
case "getEthernetStatus":
|
||||||
|
const ethernetData = JSON.parse(msg.data);
|
||||||
|
//console.log('Ethernet Status Data:', ethernetData);
|
||||||
|
$('#eth0Status').text(ethernetData.status ? ethernetData.status : 'N/A');
|
||||||
|
$('#eth0IP').text(ethernetData.ip ? ethernetData.ip : 'N/A');
|
||||||
|
$('#eth0TXBytes').text(ethernetData.txBytes ? ethernetData.txBytes : 'N/A');
|
||||||
|
$('#eth0RXBytes').text(ethernetData.rxBytes ? ethernetData.rxBytes : 'N/A');
|
||||||
|
$('#eth0TXSpeed').text(ethernetData.txSpeed ? ethernetData.txSpeed : 'N/A');
|
||||||
|
$('#eth0RXSpeed').text(ethernetData.rxSpeed ? ethernetData.rxSpeed : 'N/A');
|
||||||
|
break;
|
||||||
|
case "getModemStatus":
|
||||||
|
const modemData = JSON.parse(msg.data);
|
||||||
|
//console.log('Modem Status Data:', modemData);
|
||||||
|
$('#modemStatus').text(modemData.status ? modemData.status : 'N/A');
|
||||||
|
$('#modemIP').text(modemData.ip ? modemData.ip : 'N/A');
|
||||||
|
$('#modemTXBytes').text(modemData.txBytes ? modemData.txBytes : 'N/A');
|
||||||
|
$('#modemRXBytes').text(modemData.rxBytes ? modemData.rxBytes : 'N/A');
|
||||||
|
$('#modemTXSpeed').text(modemData.txSpeed ? modemData.txSpeed : 'N/A');
|
||||||
|
$('#modemRXSpeed').text(modemData.rxSpeed ? modemData.rxSpeed : 'N/A');
|
||||||
|
break;
|
||||||
|
case "getTunnelStatus":
|
||||||
|
const tunnelData = JSON.parse(msg.data);
|
||||||
|
//console.log('Tunnel Status Data:', tunnelData);
|
||||||
|
$('#tunnelStatus').text(tunnelData.status ? tunnelData.status : 'N/A');
|
||||||
|
$('#tunnelIP').text(tunnelData.ip ? tunnelData.ip : 'N/A');
|
||||||
|
$('#tunnelTXBytes').text(tunnelData.txBytes ? tunnelData.txBytes : 'N/A');
|
||||||
|
$('#tunnelRXBytes').text(tunnelData.rxBytes ? tunnelData.rxBytes : 'N/A');
|
||||||
|
$('#tunnelTXSpeed').text(tunnelData.txSpeed ? tunnelData.txSpeed : 'N/A');
|
||||||
|
$('#tunnelRXSpeed').text(tunnelData.rxSpeed ? tunnelData.rxSpeed : 'N/A');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = function() {
|
||||||
|
//console.log('WebSocket connection closed');
|
||||||
|
$('#indicatorDisconnected').removeClass('visually-hidden');
|
||||||
|
$('#indicatorConnected').addClass('visually-hidden');
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = function(error) {
|
||||||
|
console.error('WebSocket error:', error);
|
||||||
|
};
|
||||||
|
|
||||||
|
function sendCommand(command) {
|
||||||
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
|
ws.send(JSON.stringify(command));
|
||||||
|
} else {
|
||||||
|
console.error('WebSocket is not open. Unable to send command:', command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
260
html/webpage/hardwarestatus.html
Normal file
260
html/webpage/hardwarestatus.html
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-bs-theme="light" lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||||
|
<title>EWS_POC</title>
|
||||||
|
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="assets/css/Navbar-With-Button-icons.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-expand-md bg-body py-3">
|
||||||
|
<div class="container"><a class="navbar-brand d-flex align-items-center" href="#"><span class="bs-icon-sm bs-icon-rounded bs-icon-primary d-flex justify-content-center align-items-center me-2 bs-icon"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 16 16" class="bi bi-bezier">
|
||||||
|
<path fill-rule="evenodd" d="M0 10.5A1.5 1.5 0 0 1 1.5 9h1A1.5 1.5 0 0 1 4 10.5v1A1.5 1.5 0 0 1 2.5 13h-1A1.5 1.5 0 0 1 0 11.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zm10.5.5A1.5 1.5 0 0 1 13.5 9h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5zM6 4.5A1.5 1.5 0 0 1 7.5 3h1A1.5 1.5 0 0 1 10 4.5v1A1.5 1.5 0 0 1 8.5 7h-1A1.5 1.5 0 0 1 6 5.5zM7.5 4a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5z"></path>
|
||||||
|
<path d="M6 4.5H1.866a1 1 0 1 0 0 1h2.668A6.517 6.517 0 0 0 1.814 9H2.5c.123 0 .244.015.358.043a5.517 5.517 0 0 1 3.185-3.185A1.503 1.503 0 0 1 6 5.5zm3.957 1.358A1.5 1.5 0 0 0 10 5.5v-1h4.134a1 1 0 1 1 0 1h-2.668a6.517 6.517 0 0 1 2.72 3.5H13.5c-.123 0-.243.015-.358.043a5.517 5.517 0 0 0-3.185-3.185z"></path>
|
||||||
|
</svg></span><span>Early Warning System Receiver</span></a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||||
|
<div class="collapse navbar-collapse" id="navcol-1">
|
||||||
|
<ul class="navbar-nav me-auto">
|
||||||
|
<li class="nav-item"><a class="nav-link" href="pocreceiver.html">POC Receiver</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="prerecordedbroadcast.html">Pre-Recorded Broadcast</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="setting.html">Setting and Content</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="#">Hardware Status</a></li>
|
||||||
|
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
||||||
|
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
||||||
|
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
||||||
|
</svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorConnected" style="color: var(--bs-success);width: 26px;height: 26px;font-weight: bold;">
|
||||||
|
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
||||||
|
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-111 111-47-47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l64 64c9.4 9.4 24.6 9.4 33.9 0L369 209z"></path>
|
||||||
|
</svg></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="text-center">Hardware Status</h1>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">CPU (Average)</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">C0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">C1</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">C2</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">C3</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Temp</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="cpuUsage">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="core0Usage">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="core1Usage">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="core2Usage">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="core3Usage">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="cpuTemp">0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RAM Total</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Free</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Used</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Free %</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="ramTotal">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="ramFree">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="ramUsed">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="ramFreePercent">0.0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Disk Total</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Free</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Used</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Free %</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="diskTotal">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="diskFree">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="diskUsed">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="diskFreePercent">0.0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">ETH 0 Status</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">IP</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">TX Bytes</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RX Bytes</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">TX Speed</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RX Speed</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="eth0Status">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="eth0IP">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="eth0TXBytes">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="eth0RXBytes">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="eth0TXSpeed">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="eth0RXSpeed">0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Modem Status</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">IP</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">TX Bytes</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RX Bytes</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">TX Speed</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RX Speed</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="modemStatus">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="modemIP">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="modemTXBytes">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="modemRXBytes">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="modemTXSpeed">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="modemRXSpeed">0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">Tunnel Status</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">IP</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">TX Bytes</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RX Bytes</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">TX Speed</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="fw-bold d-flex h-100 justify-content-center align-items-center">RX Speed</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="tunnelStatus">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="tunnelIP">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="tunnelTXBytes">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="tunnelRXBytes">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 col-sm-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="tunnelTXSpeed">0.0</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 col-md-2">
|
||||||
|
<p class="d-flex h-100 justify-content-center align-items-center" id="tunnelRXSpeed">0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="assets/js/jquery-3.7.1.min.js"></script>
|
||||||
|
<script src="assets/js/hardwarestatus.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
<li class="nav-item"><a class="nav-link active" href="#">POC Receiver</a></li>
|
<li class="nav-item"><a class="nav-link active" href="#">POC Receiver</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="prerecordedbroadcast.html">Pre-Recorded Broadcast</a></li>
|
<li class="nav-item"><a class="nav-link" href="prerecordedbroadcast.html">Pre-Recorded Broadcast</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="setting.html">Setting and Content</a></li>
|
<li class="nav-item"><a class="nav-link" href="setting.html">Setting and Content</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="hardwarestatus.html">Hardware Status</a></li>
|
||||||
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
||||||
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
||||||
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
||||||
@@ -35,7 +36,7 @@
|
|||||||
<h1 class="text-center">Zello Status</h1>
|
<h1 class="text-center">Zello Status</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<p class="d-flex justify-content-center" id="zelloStatus">Paragraph</p>
|
<p class="d-flex justify-content-center" id="zelloStatus">No Status</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<li class="nav-item"><a class="nav-link" href="pocreceiver.html">POC Receiver</a></li>
|
<li class="nav-item"><a class="nav-link" href="pocreceiver.html">POC Receiver</a></li>
|
||||||
<li class="nav-item"><a class="nav-link active" href="#">Pre-Recorded Broadcast</a></li>
|
<li class="nav-item"><a class="nav-link active" href="#">Pre-Recorded Broadcast</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="setting.html">Setting and Content</a></li>
|
<li class="nav-item"><a class="nav-link" href="setting.html">Setting and Content</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="hardwarestatus.html">Hardware Status</a></li>
|
||||||
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
||||||
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
||||||
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<li class="nav-item"><a class="nav-link" href="pocreceiver.html">POC Receiver</a></li>
|
<li class="nav-item"><a class="nav-link" href="pocreceiver.html">POC Receiver</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="prerecordedbroadcast.html">Pre-Recorded Broadcast</a></li>
|
<li class="nav-item"><a class="nav-link" href="prerecordedbroadcast.html">Pre-Recorded Broadcast</a></li>
|
||||||
<li class="nav-item"><a class="nav-link active" href="#">Setting and Content</a></li>
|
<li class="nav-item"><a class="nav-link active" href="#">Setting and Content</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link" href="hardwarestatus.html">Hardware Status</a></li>
|
||||||
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
</ul><a class="btn btn-primary" role="button" href="index.html">Logout<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" class="visually-hidden" id="indicatorDisconnected" style="color: var(--bs-danger);width: 26px;height: 26px;font-weight: bold;">
|
||||||
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
|
||||||
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
<path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"></path>
|
||||||
@@ -168,14 +169,9 @@
|
|||||||
<div class="row w-100">
|
<div class="row w-100">
|
||||||
<h1 class="text-center">Content Upload</h1>
|
<h1 class="text-center">Content Upload</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="row"><input type="file" id="chosenFile"></div>
|
<div class="row w-100">
|
||||||
<div class="row">
|
<div class="col-10"><input type="file" id="chosenFile"></div>
|
||||||
<div class="col">
|
<div class="col-2"><button class="btn btn-primary" id="btnUploadContent" type="button">Upload</button></div>
|
||||||
<div class="progress h-100" id="contentUploadProgress">
|
|
||||||
<div class="progress-bar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" style="width: 50%;">50%</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-2"><button class="btn btn-primary mt-2 mb-2" id="btnUploadContent" type="button">Upload</button></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
|||||||
90
src/Main.kt
90
src/Main.kt
@@ -12,32 +12,110 @@ import zello.ZelloEvent
|
|||||||
import javafx.util.Pair
|
import javafx.util.Pair
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import sbc.DigitalOutput
|
import sbc.DigitalOutput
|
||||||
import sbc.NanopiDuo2
|
import sbc.NanopiDuo2
|
||||||
|
import sbc.SbcInfo
|
||||||
|
import sbc.cpuinfo
|
||||||
|
import sbc.meminfo
|
||||||
|
import sbc.netdev
|
||||||
import somecodes.Codes
|
import somecodes.Codes
|
||||||
|
import somecodes.Codes.Companion.isLinux
|
||||||
import web.WsCommand
|
import web.WsCommand
|
||||||
import java.util.function.BiFunction
|
import java.util.function.BiFunction
|
||||||
|
|
||||||
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
|
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
|
||||||
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
|
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
|
||||||
fun main() {
|
fun main() {
|
||||||
|
// change when updating the application
|
||||||
|
val appversion = "0.1.1"
|
||||||
val logger = LoggerFactory.getLogger("Main")
|
val logger = LoggerFactory.getLogger("Main")
|
||||||
val objectMapper = jacksonObjectMapper()
|
val objectMapper = jacksonObjectMapper()
|
||||||
logger.info("Application started, version 0.0.8")
|
logger.info("Application started, version $appversion")
|
||||||
|
|
||||||
val cfg = configFile()
|
val cfg = configFile()
|
||||||
cfg.Load()
|
cfg.Load()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coroutine scope for the application
|
||||||
|
*/
|
||||||
|
val appscope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* various SBC related functions and information
|
||||||
|
*/
|
||||||
|
var sbc : SbcInfo?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu information, one time read
|
||||||
|
*/
|
||||||
|
var cpuinfo: cpuinfo?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ram information, will be updated periodically in appscope
|
||||||
|
*/
|
||||||
|
var raminfo: meminfo?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu statistics, will be updated periodically in appscope
|
||||||
|
* key is cpu name
|
||||||
|
* value is cpu utilization percentage
|
||||||
|
* e.g. cpustat["cpu0"] = 12.5
|
||||||
|
*/
|
||||||
|
val cpustat = HashMap<String, Double>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* network statistics, will be updated periodically in appscope
|
||||||
|
* key is network interface name
|
||||||
|
* value is a Pair of strings, first is RX transfer speed per second, second is TX transfer speed per second
|
||||||
|
*/
|
||||||
|
val networkstat = HashMap<String, Pair<String, String>>()
|
||||||
|
|
||||||
|
if (isLinux()){
|
||||||
|
sbc = SbcInfo()
|
||||||
|
cpuinfo = sbc.getCpuInfo()
|
||||||
|
//logger.info("CPU Info: ${cpuinfo?.hardware?:"N/A"}, Cores: ${cpuinfo?.core?:"N/A"}, SerialNumber: ${cpuinfo?.serialNumber?:"N/A"}")
|
||||||
|
|
||||||
|
appscope.launch {
|
||||||
|
// run while the application is active
|
||||||
|
while(isActive){
|
||||||
|
raminfo = sbc.getMemInfo()
|
||||||
|
//logger.info(raminfo?.toString() ?: "Failed to get RAM info")
|
||||||
|
sbc.getCpuUtilization { it ->
|
||||||
|
// result will come 1 second later, as array of pairs,
|
||||||
|
// with first being cpu name and second being utilization percentage
|
||||||
|
it.forEach { cpuinfo ->
|
||||||
|
cpustat[cpuinfo.first] = cpuinfo.second
|
||||||
|
}
|
||||||
|
//logger.info("CPU Utilization: ${cpustat.map { "${it.key.ifBlank { "avg" }}: ${ it.value}%" }}")
|
||||||
|
}
|
||||||
|
sbc.getNetworkTransferSpeed { it ->
|
||||||
|
// result will come 1 second later, as map of network interface name to Pair of RX and TX speeds
|
||||||
|
it.forEach { xx ->
|
||||||
|
networkstat[xx.key] = Pair(
|
||||||
|
netdev.toText(xx.value.first)+ "/s",
|
||||||
|
netdev.toText(xx.value.second) + "/s"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
//logger.info("Network Transfer Speed: ${networkstat.map { "${it.key}: RX=${it.value.key}, TX=${it.value.value}" }}")
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(5000) // Update every 5 seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var relay1 : DigitalOutput? = null
|
var relay1 : DigitalOutput? = null
|
||||||
var relay2 : DigitalOutput? = null
|
var relay2 : DigitalOutput? = null
|
||||||
var commandLED : DigitalOutput? = null
|
var commandLED : DigitalOutput? = null
|
||||||
var streamingLED : DigitalOutput? = null
|
var streamingLED : DigitalOutput? = null
|
||||||
|
|
||||||
runBlocking {
|
appscope.launch {
|
||||||
relay1 = DigitalOutput(NanopiDuo2.CLK.linuxGpio, "Relay1", true)
|
relay1 = DigitalOutput(NanopiDuo2.CLK.linuxGpio, "Relay1", true)
|
||||||
relay2 = DigitalOutput(NanopiDuo2.MISO.linuxGpio, "Relay2", true)
|
relay2 = DigitalOutput(NanopiDuo2.MISO.linuxGpio, "Relay2", true)
|
||||||
commandLED = DigitalOutput(NanopiDuo2.TX1.linuxGpio, "CommandLED", true)
|
commandLED = DigitalOutput(NanopiDuo2.TX1.linuxGpio, "CommandLED", true)
|
||||||
@@ -48,7 +126,6 @@ fun main() {
|
|||||||
streamingLED.setOFF()
|
streamingLED.setOFF()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var audioID = 0
|
var audioID = 0
|
||||||
val preferedAudioDevice = "USB Audio"
|
val preferedAudioDevice = "USB Audio"
|
||||||
AudioUtility.LoadLibraries()
|
AudioUtility.LoadLibraries()
|
||||||
@@ -147,12 +224,13 @@ fun main() {
|
|||||||
relay1?.setOFF()
|
relay1?.setOFF()
|
||||||
relay2?.setOFF()
|
relay2?.setOFF()
|
||||||
val e = this
|
val e = this
|
||||||
CoroutineScope(Dispatchers.Default).launch {
|
|
||||||
|
|
||||||
|
appscope.launch {
|
||||||
delay(10000) // Wait for 10 seconds before trying to reconnect
|
delay(10000) // Wait for 10 seconds before trying to reconnect
|
||||||
z = CreateZelloFromConfig()
|
z = CreateZelloFromConfig()
|
||||||
z.Start(e)
|
z.Start(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(errorMessage: String) {
|
override fun onError(errorMessage: String) {
|
||||||
|
|||||||
39
src/sbc/RaspberryPi4.kt
Normal file
39
src/sbc/RaspberryPi4.kt
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raspberry Pi 4 pin and GPIO mapping.
|
||||||
|
* Source : https://pinout.xyz/#
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
enum class RaspberryPi4(val pin: Int, val linuxGpio: Int, val alias:String? = null) {
|
||||||
|
GPIO2(3, 2, "SDA1"),
|
||||||
|
GPIO3(5, 3, "SCL1"),
|
||||||
|
GPIO4(7, 4, "GPCLK0"),
|
||||||
|
GPIO17(11, 17),
|
||||||
|
GPIO27(13, 27),
|
||||||
|
GPIO10(19, 10, "MOSI"),
|
||||||
|
GPIO9(21, 9, "MISO"),
|
||||||
|
GPIO11(23, 11, "SCLK"),
|
||||||
|
GPIO0(27, 0,"EEPROM SDA"),
|
||||||
|
GPIO5(29, 5),
|
||||||
|
GPIO6(31, 6),
|
||||||
|
GPIO13(33, 13,"PWM1"),
|
||||||
|
GPIO19(35, 19, "PCM FS"),
|
||||||
|
GPIO26(37, 26),
|
||||||
|
|
||||||
|
GPIO14(8, 14, "TXD"),
|
||||||
|
GPIO15(10, 15, "RXD"),
|
||||||
|
GPIO18(12, 18, "PCM CLK"),
|
||||||
|
GPIO23(16, 23),
|
||||||
|
GPIO24(18, 24),
|
||||||
|
GPIO25(22, 25),
|
||||||
|
GPIO8(24, 8,"SPI CE0"),
|
||||||
|
GPIO7(26, 7, "SPI CE1"),
|
||||||
|
GPIO1(28, 1, "EEPROM SCL"),
|
||||||
|
GPIO12(32, 12, "PWM0"),
|
||||||
|
GPIO16(36, 16),
|
||||||
|
GPIO20(38, 20,"PCM DIN"),
|
||||||
|
GPIO21(40, 21, "PCM DOUT"),;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
300
src/sbc/SbcInfo.kt
Normal file
300
src/sbc/SbcInfo.kt
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import somecodes.Codes.Companion.isLinux
|
||||||
|
import java.io.File
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.exists
|
||||||
|
import kotlin.io.path.readText
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get SBC Information
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
class SbcInfo {
|
||||||
|
private val logger = LoggerFactory.getLogger("SbcInfo")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get CPU information from /proc/cpuinfo on Linux systems.
|
||||||
|
* @return cpuinfo data class containing core count, hardware model, and serial number.
|
||||||
|
* Returns null if the platform is not Linux or if an error occurs while reading the file
|
||||||
|
*/
|
||||||
|
fun getCpuInfo(): cpuinfo? {
|
||||||
|
return try {
|
||||||
|
if (isLinux()) {
|
||||||
|
val lines = File("/proc/cpuinfo").readLines()
|
||||||
|
if (lines.isNotEmpty()) {
|
||||||
|
val core = lines.count { it.startsWith("processor") }
|
||||||
|
val hardware =
|
||||||
|
lines.firstOrNull { it.startsWith("Hardware") }?.substringAfter(":")?.trim() ?: "Unknown"
|
||||||
|
val serialNumber =
|
||||||
|
lines.firstOrNull { it.startsWith("Serial") }?.substringAfter(":")?.trim() ?: "Unknown"
|
||||||
|
cpuinfo(core, hardware, serialNumber)
|
||||||
|
} else {
|
||||||
|
logger.error("No CPU info found in /proc/cpuinfo")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.error("Platform is not Linux, cannot get CPU info")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("Error getting CPU info: ${e.message}")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get memory information from /proc/meminfo on Linux systems.
|
||||||
|
* @return meminfo data class containing total, free, available memory, buffers, cached memory, and swap info.
|
||||||
|
* Returns null if the platform is not Linux or if an error occurs while reading the file
|
||||||
|
*/
|
||||||
|
fun getMemInfo(): meminfo? {
|
||||||
|
return try {
|
||||||
|
if (isLinux()) {
|
||||||
|
val memInfoFile = File("/proc/meminfo")
|
||||||
|
if (memInfoFile.exists()) {
|
||||||
|
val lines = memInfoFile.readLines()
|
||||||
|
val totalMem =
|
||||||
|
lines.firstOrNull { it.startsWith("MemTotal:") }?.substringAfter(":")?.trim()?.split(" ")
|
||||||
|
?.first()?.toLongOrNull() ?: 0L
|
||||||
|
val freeMem =
|
||||||
|
lines.firstOrNull { it.startsWith("MemFree:") }?.substringAfter(":")?.trim()?.split(" ")
|
||||||
|
?.first()?.toLongOrNull() ?: 0L
|
||||||
|
val availableMem =
|
||||||
|
lines.firstOrNull { it.startsWith("MemAvailable:") }?.substringAfter(":")?.trim()?.split(" ")
|
||||||
|
?.first()?.toLongOrNull() ?: 0L
|
||||||
|
val buffers =
|
||||||
|
lines.firstOrNull { it.startsWith("Buffers:") }?.substringAfter(":")?.trim()?.split(" ")
|
||||||
|
?.first()?.toLongOrNull() ?: 0L
|
||||||
|
val cached =
|
||||||
|
lines.firstOrNull { it.startsWith("Cached:") }?.substringAfter(":")?.trim()?.split(" ")?.first()
|
||||||
|
?.toLongOrNull() ?: 0L
|
||||||
|
val swapTotal =
|
||||||
|
lines.firstOrNull { it.startsWith("SwapTotal:") }?.substringAfter(":")?.trim()?.split(" ")
|
||||||
|
?.first()?.toLongOrNull() ?: 0L
|
||||||
|
val swapFree = lines.firstOrNull { it.startsWith("SwapFree:") }
|
||||||
|
meminfo(
|
||||||
|
totalMem,
|
||||||
|
freeMem,
|
||||||
|
availableMem,
|
||||||
|
buffers,
|
||||||
|
cached,
|
||||||
|
swapTotal,
|
||||||
|
swapFree?.substringAfter(":")?.trim()?.split(" ")?.first()?.toLongOrNull() ?: 0L
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logger.error("/proc/meminfo does not exist")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Platform is not Linux, cannot get memory info")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("Error getting memory info: ${e.message}")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get CPU utilization percentage for each CPU core.
|
||||||
|
* @param percent Consumer that accepts an array of pairs containing CPU core names and their utilization percentages.
|
||||||
|
* This function runs in a coroutine and retrieves CPU usage from /proc/stat on Linux systems.
|
||||||
|
*/
|
||||||
|
fun getCpuUtilization(percent: Consumer<Array<Pair<String, Double>>>) {
|
||||||
|
if (isLinux()) {
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
val map1 = HashMap<String, cpustat>()
|
||||||
|
val map2 = HashMap<String, cpustat>()
|
||||||
|
val s1 = File("/proc/stat").readLines().filter { it.startsWith("cpu") }
|
||||||
|
s1.forEach {
|
||||||
|
val match = cpustat.regex.find(it)
|
||||||
|
if (match != null) {
|
||||||
|
val parts = match.groupValues
|
||||||
|
if (parts.size >= 11) {
|
||||||
|
val first = cpustat(
|
||||||
|
user = parts[2].toLong(),
|
||||||
|
nice = parts[3].toLong(),
|
||||||
|
system = parts[4].toLong(),
|
||||||
|
idle = parts[5].toLong(),
|
||||||
|
iowait = parts[6].toLong(),
|
||||||
|
irq = parts[7].toLong(),
|
||||||
|
softirq = parts[8].toLong(),
|
||||||
|
steal = parts[9].toLong(),
|
||||||
|
guest = parts[10].toLongOrNull() ?: 0L,
|
||||||
|
guestNice = parts.getOrNull(11)?.toLongOrNull() ?: 0L
|
||||||
|
)
|
||||||
|
map1[parts[1].trim()] = first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(1000) // Wait for 1 second to get a new snapshot
|
||||||
|
val s2 = File("/proc/stat").readLines().filter { it.startsWith("cpu") }
|
||||||
|
s2.forEach {
|
||||||
|
val match = cpustat.regex.find(it)
|
||||||
|
if (match != null) {
|
||||||
|
val parts = match.groupValues
|
||||||
|
if (parts.size >= 11) {
|
||||||
|
val second = cpustat(
|
||||||
|
user = parts[2].toLong(),
|
||||||
|
nice = parts[3].toLong(),
|
||||||
|
system = parts[4].toLong(),
|
||||||
|
idle = parts[5].toLong(),
|
||||||
|
iowait = parts[6].toLong(),
|
||||||
|
irq = parts[7].toLong(),
|
||||||
|
softirq = parts[8].toLong(),
|
||||||
|
steal = parts[9].toLong(),
|
||||||
|
guest = parts[10].toLongOrNull() ?: 0L,
|
||||||
|
guestNice = parts.getOrNull(11)?.toLongOrNull() ?: 0L
|
||||||
|
)
|
||||||
|
map2[parts[1].trim()] = second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare s1 and s2
|
||||||
|
val result = ArrayList<Pair<String, Double>>()
|
||||||
|
map1.forEach {
|
||||||
|
val key = it.key
|
||||||
|
val firstStat = it.value
|
||||||
|
val secondStat = map2[key]
|
||||||
|
if (secondStat != null) {
|
||||||
|
val usage = secondStat.cpuUsage(firstStat)
|
||||||
|
result.add(Pair(key, usage))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
percent.accept(result.toTypedArray())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Platform is not Linux, cannot get CPU utilization")
|
||||||
|
percent.accept(arrayOf(Pair("N/A", 0.0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get network status from /proc/net/dev on Linux systems.
|
||||||
|
* @return List of netdev data class containing network device name, RX and TX statistics.
|
||||||
|
* Returns null if the platform is not Linux or if an error occurs while reading the file
|
||||||
|
*/
|
||||||
|
fun getNetworkStatus(): List<netdev>? {
|
||||||
|
return try {
|
||||||
|
if (isLinux()) {
|
||||||
|
val netdevFile = File("/proc/net/dev")
|
||||||
|
if (netdevFile.exists()) {
|
||||||
|
val lines = netdevFile.readLines().drop(2) // Skip the first two header lines
|
||||||
|
val regex = netdev.regex
|
||||||
|
val devices = lines.mapNotNull { line ->
|
||||||
|
val match = regex.find(line)
|
||||||
|
if (match != null) {
|
||||||
|
val parts = match.groupValues
|
||||||
|
val name = parts[1].trim().removeSuffix(":")
|
||||||
|
val rx = devstat(
|
||||||
|
Bytes = parts[2].toLong(),
|
||||||
|
Packets = parts[3].toLong(),
|
||||||
|
Errors = parts[4].toLong(),
|
||||||
|
Drops = parts[5].toLong(),
|
||||||
|
Fifo = parts[6].toLong(),
|
||||||
|
Frame = parts[7].toLong(),
|
||||||
|
Compressed = parts[8].toLong(),
|
||||||
|
Multicast = parts[9].toLong()
|
||||||
|
)
|
||||||
|
val tx = devstat(
|
||||||
|
Bytes = parts[10].toLong(),
|
||||||
|
Packets = parts[11].toLong(),
|
||||||
|
Errors = parts[12].toLong(),
|
||||||
|
Drops = parts[13].toLong(),
|
||||||
|
Fifo = parts[14].toLong(),
|
||||||
|
Frame = parts[15].toLong(),
|
||||||
|
Compressed = parts[16].toLong(),
|
||||||
|
Multicast = parts[17].toLong()
|
||||||
|
)
|
||||||
|
netdev(name, rx, tx)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
devices
|
||||||
|
} else {
|
||||||
|
logger.error("/proc/net/dev does not exist")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Platform is not Linux, cannot get network status")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("Error getting network status: ${e.message}")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get network transfer speed for each network device.
|
||||||
|
* @param callback Consumer that accepts a map where keys are network device names and values are
|
||||||
|
* pairs of RX and TX bytes difference within a 1-second interval.
|
||||||
|
* This function runs in a coroutine and retrieves network statistics from /proc/net/dev on Linux
|
||||||
|
*/
|
||||||
|
fun getNetworkTransferSpeed(callback: Consumer<Map<String, Pair<Long, Long>>>) {
|
||||||
|
if (isLinux()) {
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
val netdevs = getNetworkStatus()
|
||||||
|
if (netdevs != null) {
|
||||||
|
val speedMap = netdevs.associate {
|
||||||
|
it.name to Pair(it.RX.Bytes, it.TX.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1000) // Wait for 1 second to get a new snapshot
|
||||||
|
|
||||||
|
val newNetdevs = getNetworkStatus()
|
||||||
|
if (newNetdevs != null) {
|
||||||
|
val newSpeedMap = newNetdevs.associate {
|
||||||
|
it.name to Pair(it.RX.Bytes, it.TX.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
val resultMap = mutableMapOf<String, Pair<Long, Long>>()
|
||||||
|
speedMap.forEach { (name, oldSpeed) ->
|
||||||
|
val newSpeed = newSpeedMap[name]
|
||||||
|
if (newSpeed != null) {
|
||||||
|
val rxDiff = newSpeed.first - oldSpeed.first
|
||||||
|
val txDiff = newSpeed.second - oldSpeed.second
|
||||||
|
resultMap[name] = Pair(rxDiff, txDiff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback.accept(resultMap)
|
||||||
|
|
||||||
|
} else callback.accept(emptyMap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("Platform is not Linux, cannot get network transfer speed")
|
||||||
|
callback.accept(emptyMap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get CPU Thermal information from /sys/class/thermal/thermal_zone0/temp on Linux systems.
|
||||||
|
* @return CPU temperature in degrees Celsius. Returns 0.0 if the platform is not Linux or if an error occurs while reading the file.
|
||||||
|
*/
|
||||||
|
fun getCPUThermal(): Double {
|
||||||
|
return try{
|
||||||
|
if (isLinux()){
|
||||||
|
val p = Path("/sys/class/thermal/thermal_zone0/temp")
|
||||||
|
if (p.exists()) {
|
||||||
|
val vv = p.readText().trim().toDouble()
|
||||||
|
val tempCelsius = vv / 1000.0 // Convert from millidegrees Celsius to degrees Celsius
|
||||||
|
(tempCelsius*10).toInt() / 10.0 // Round to 1 decimal places
|
||||||
|
} else throw Exception("/sys/class/thermal/thermal_zone0/temp does not exist")
|
||||||
|
} else throw Exception("Platform is not Linux, cannot get CPU thermal info")
|
||||||
|
} catch (_ : Exception) {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/sbc/cpuinfo.kt
Normal file
3
src/sbc/cpuinfo.kt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
data class cpuinfo(val core: Int, val hardware: String, val serialNumber: String)
|
||||||
49
src/sbc/cpustat.kt
Normal file
49
src/sbc/cpustat.kt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class representing CPU statistics.
|
||||||
|
* @property user Time spent in user mode.
|
||||||
|
* @property nice Time spent in user mode with low priority (nice).
|
||||||
|
* @property system Time spent in system mode.
|
||||||
|
* @property idle Time spent in idle mode.
|
||||||
|
* @property iowait Time spent waiting for I/O operations to complete.
|
||||||
|
* @property irq Time spent servicing hardware interrupts.
|
||||||
|
* @property softirq Time spent servicing software interrupts.
|
||||||
|
* @property steal Time spent in involuntary wait by virtual CPUs.
|
||||||
|
* @property guest Time spent running a virtual CPU for guest operating systems.
|
||||||
|
* @property guestNice Time spent running a virtual CPU for guest operating systems with low priority (nice).
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
class cpustat(val user: Long, val nice: Long, val system: Long, val idle: Long, val iowait: Long, val irq: Long, val softirq: Long, val steal: Long, val guest: Long, val guestNice: Long) {
|
||||||
|
companion object{
|
||||||
|
val regex = Regex("""cpu(\d?)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)""")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "CPU Stat(user=$user, nice=$nice, system=$system, idle=$idle, iowait=$iowait, irq=$irq, softirq=$softirq)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun total(): Long {
|
||||||
|
return user + nice + system + idle + iowait + irq + softirq + steal + guest + guestNice
|
||||||
|
}
|
||||||
|
|
||||||
|
fun idle(): Long {
|
||||||
|
return idle + iowait
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate CPU usage percentage based on the current and previous cpustat instances.
|
||||||
|
* @param previous The previous cpustat instance to compare against.
|
||||||
|
* @return CPU usage percentage as a Double, rounded to one decimal place.
|
||||||
|
*/
|
||||||
|
fun cpuUsage(previous: cpustat): Double {
|
||||||
|
val totalDiff = total() - previous.total()
|
||||||
|
if (totalDiff < 0L) return 0.0 // Avoid division by zero
|
||||||
|
val idleDiff = idle() - previous.idle()
|
||||||
|
if (idleDiff < 0L) return 0.0 // Avoid negative idle difference
|
||||||
|
return (1.0*(totalDiff - idleDiff) / totalDiff * 100.0).let {
|
||||||
|
val x = (it * 10).toInt()
|
||||||
|
x/10.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/sbc/devstat.kt
Normal file
5
src/sbc/devstat.kt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
data class devstat(val Bytes: Long, val Packets: Long, val Errors: Long, val Drops: Long, val Fifo: Long, val Frame: Long, val Compressed: Long, val Multicast: Long)
|
||||||
|
|
||||||
|
|
||||||
76
src/sbc/meminfo.kt
Normal file
76
src/sbc/meminfo.kt
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memory Information data class from /proc/meminfo on Linux systems.
|
||||||
|
* all values are in kilobytes (KB).
|
||||||
|
* @property MemTotal Total usable RAM (i.e., physical RAM minus a few reserved bits and the kernel binary code).
|
||||||
|
* @property MemFree The amount of physical RAM, in kilobytes, left unused by the system.
|
||||||
|
* @property MemAvailable An estimate of how much memory is available for starting new applications, without swapping.
|
||||||
|
* @property Buffers The amount of memory, in kilobytes, used by kernel buffers.
|
||||||
|
* @property Cached The amount of memory, in kilobytes, used by the page cache and slabs.
|
||||||
|
* @property SwapTotal Total amount of swap space available, in kilobytes.
|
||||||
|
* @property SwapFree The amount of swap space that is currently unused, in kilobytes.
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
class meminfo(val MemTotal: Long, val MemFree: Long, val MemAvailable: Long, val Buffers: Long, val Cached: Long, val SwapTotal: Long, val SwapFree: Long) {
|
||||||
|
companion object{
|
||||||
|
private const val MB_Threshold = 1024.0
|
||||||
|
private const val GB_Threshold = 1024.0 * MB_Threshold
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a memory value in kilobytes to a human-readable string.
|
||||||
|
* @param value The memory value in kilobytes.
|
||||||
|
* @return A string representation of the memory value in GB, MB, or KB, and round to two decimal places.
|
||||||
|
* For example, "1.50 GB", "512 MB", or "256 KB
|
||||||
|
*/
|
||||||
|
fun toText(value: Long) : String {
|
||||||
|
return when {
|
||||||
|
value >= 1024 * 1024 -> "${"%.2f".format(value / GB_Threshold)} GB"
|
||||||
|
value >= 1024 -> "${"%.2f".format(value / MB_Threshold)} MB"
|
||||||
|
else -> "$value KB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "MemTotal=${toText(MemTotal)}, MemFree=${toText(MemFree)}, MemAvailable=${toText(MemAvailable)}, Buffers=${toText(Buffers)}, Cached=${toText(Cached)}, SwapTotal=${toText(SwapTotal)}, SwapFree=${toText(SwapFree)}, "
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the used memory in kilobytes.
|
||||||
|
* @return The amount of used memory in kilobytes.
|
||||||
|
*/
|
||||||
|
fun MemUsed(): Long {
|
||||||
|
return MemTotal - MemFree
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the percentage of memory used.
|
||||||
|
* @return The percentage of memory used, as a double, rounded to two decimal places.
|
||||||
|
*/
|
||||||
|
fun percentUsed(): Double {
|
||||||
|
return if (MemTotal > 0) {
|
||||||
|
((1.0 * MemUsed() / MemTotal) * 100.0).let {
|
||||||
|
val x = (it * 100).toInt()
|
||||||
|
x / 100.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the percentage of memory available.
|
||||||
|
* @return The percentage of memory available, as a double, rounded to two decimal places.
|
||||||
|
*/
|
||||||
|
fun percentFree(): Double {
|
||||||
|
return if (MemTotal > 0) {
|
||||||
|
((1.0 * MemFree / MemTotal) * 100.0).let {
|
||||||
|
val x = (it * 100).toInt()
|
||||||
|
x/ 100.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/sbc/netdev.kt
Normal file
28
src/sbc/netdev.kt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package sbc
|
||||||
|
|
||||||
|
class netdev( val name: String,val RX: devstat, val TX: devstat) {
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
val regex = Regex("""\s?(\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+)""")
|
||||||
|
private const val KB_Size = 1024.0
|
||||||
|
private const val MB_Size = KB_Size * 1024.0
|
||||||
|
private const val GB_Size = MB_Size * 1024.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a long value to a human-readable text format.
|
||||||
|
* @param value The long value to convert.
|
||||||
|
* @return A string representation of the value, formatted with appropriate units.
|
||||||
|
* The value is formatted in bytes, kilobytes, megabytes, or gigabytes, and rounded to one decimal place.
|
||||||
|
*/
|
||||||
|
fun toText(value: Long): String {
|
||||||
|
return when {
|
||||||
|
value >= 1024 * 1024 * 1024 -> "${"%.1f".format(value / (GB_Size))} GB"
|
||||||
|
value >= 1024 * 1024 -> "${"%.1f".format(value / (MB_Size))} MB"
|
||||||
|
value >= 1024 -> "${"%.1f".format(value / KB_Size)} KB"
|
||||||
|
else -> "$value B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,9 +16,13 @@ class Codes {
|
|||||||
val gpioUnexportPath : Path = gpioPath.resolve("unexport")
|
val gpioUnexportPath : Path = gpioPath.resolve("unexport")
|
||||||
private val logger = LoggerFactory.getLogger("Codes")
|
private val logger = LoggerFactory.getLogger("Codes")
|
||||||
private val validAudioExtensions = setOf("wav", "mp3")
|
private val validAudioExtensions = setOf("wav", "mp3")
|
||||||
private const val KB_size = 1024 // 1 KB = 1024 bytes
|
private const val KB_size = 1024.0 // 1 KB = 1024 bytes
|
||||||
private const val MB_size = 1024 * KB_size // 1 MB = 1024 KB
|
private const val MB_size = 1024.0 * KB_size // 1 MB = 1024 KB
|
||||||
private const val GB_size = 1024 * MB_size // 1 GB = 1024 MB
|
private const val GB_size = 1024.0 * MB_size // 1 GB = 1024 MB
|
||||||
|
|
||||||
|
fun isLinux() : Boolean {
|
||||||
|
return Platform.isLinux()
|
||||||
|
}
|
||||||
|
|
||||||
fun haveGpioSupport() : Boolean {
|
fun haveGpioSupport() : Boolean {
|
||||||
if (Platform.isLinux()){
|
if (Platform.isLinux()){
|
||||||
@@ -33,9 +37,9 @@ class Codes {
|
|||||||
|
|
||||||
fun SizeToString(size: Long) : String {
|
fun SizeToString(size: Long) : String {
|
||||||
return when {
|
return when {
|
||||||
size >= GB_size -> String.format("%.2f GB", size.toDouble() / GB_size)
|
size >= GB_size -> String.format("%.2f GB", size / GB_size)
|
||||||
size >= MB_size -> String.format("%.2f MB", size.toDouble() / MB_size)
|
size >= MB_size -> String.format("%.2f MB", size / MB_size)
|
||||||
size >= KB_size -> String.format("%.2f KB", size.toDouble() / KB_size)
|
size >= KB_size -> String.format("%.2f KB", size / KB_size)
|
||||||
else -> "$size bytes"
|
else -> "$size bytes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user