database
This commit is contained in:
175
html/database.html
Normal file
175
html/database.html
Normal file
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>NebuleAir</title>
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<style>
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#sidebar a.nav-link {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
#sidebar a.nav-link:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
#sidebar a.nav-link svg {
|
||||
margin-right: 8px; /* Add spacing between icons and text */
|
||||
}
|
||||
#sidebar {
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
.offcanvas-backdrop {
|
||||
z-index: 1040;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Topbar -->
|
||||
<span id="topbar"></span>
|
||||
|
||||
<!-- Sidebar Offcanvas for Mobile -->
|
||||
<div class="offcanvas offcanvas-start text-white bg-dark" tabindex="-1" id="sidebarOffcanvas" aria-labelledby="sidebarOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="sidebarOffcanvasLabel">NebuleAir</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body" id="sidebar_mobile">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid mt-5">
|
||||
<div class="row">
|
||||
<aside class="col-md-2 col-lg-1 d-none d-md-block vh-100 position-fixed bg-dark text-white" id="sidebar">
|
||||
</aside>
|
||||
<!-- Main content -->
|
||||
<main class="col-md-10 ms-sm-auto col-lg-11 offset-md-2 offset-lg-1 px-md-4">
|
||||
<h1 class="mt-4">Base de données</h1>
|
||||
<p>Le capteur enregistre en local les données de mesures. Vous pouvez ici les consulter et les télécharger.</p>
|
||||
|
||||
<div class="row mb-3">
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="card text-dark bg-light">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Consulter Base de donnée</h5>
|
||||
<p class="card-text">General information.</p>
|
||||
<button class="btn btn-primary" onclick="get_internet()">Get Data</button>
|
||||
<table class="table table-striped-columns">
|
||||
<tbody id="data-table-body_internet_general"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="card text-dark bg-light">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Télécharger les données</h5>
|
||||
<p class="card-text">Scan des réseaux WIFI disponibles.</p>
|
||||
<button class="btn btn-primary" onclick="wifi_scan()">Download</button>
|
||||
<table class="table">
|
||||
<tbody id="data-table-body_wifi_scan"></tbody>
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JAVASCRIPT -->
|
||||
|
||||
<!-- Link Ajax locally -->
|
||||
<script src="assets/jquery/jquery-3.7.1.min.js"></script>
|
||||
<!-- Link Bootstrap JS and Popper.js locally -->
|
||||
<script src="assets/js/bootstrap.bundle.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
console.log("DOMContentLoaded");
|
||||
|
||||
const elementsToLoad = [
|
||||
{ id: 'topbar', file: 'topbar.html' },
|
||||
{ id: 'sidebar', file: 'sidebar.html' },
|
||||
{ id: 'sidebar_mobile', file: 'sidebar.html' }
|
||||
];
|
||||
|
||||
elementsToLoad.forEach(({ id, file }) => {
|
||||
fetch(file)
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
element.innerHTML = data;
|
||||
}
|
||||
})
|
||||
.catch(error => console.error(`Error loading ${file}:`, error));
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
window.onload = function() {
|
||||
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
|
||||
.then(response => response.json()) // Parse response as JSON
|
||||
.then(data => {
|
||||
console.log("Getting config file (onload)");
|
||||
//get device ID
|
||||
const deviceID = data.deviceID.trim().toUpperCase();
|
||||
//document.getElementById('pageTitle_plus_ID').innerText = 'token: ' + deviceID;
|
||||
|
||||
//get device Name
|
||||
const deviceName = data.deviceName;
|
||||
|
||||
const elements = document.querySelectorAll('.sideBar_sensorName');
|
||||
elements.forEach((element) => {
|
||||
element.innerText = deviceName;
|
||||
});
|
||||
|
||||
|
||||
//get local RTC
|
||||
$.ajax({
|
||||
url: 'launcher.php?type=RTC_time',
|
||||
dataType: 'text', // Specify that you expect a JSON response
|
||||
method: 'GET', // Use GET or POST depending on your needs
|
||||
success: function(response) {
|
||||
console.log("Local RTC: " + response);
|
||||
const RTC_Element = document.getElementById("RTC_time");
|
||||
RTC_Element.textContent = response;
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('AJAX request failed:', status, error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
.catch(error => console.error('Error loading config.json:', error));
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -64,6 +64,7 @@
|
||||
<div id="disk_space"></div>
|
||||
<p class="card-text">Memory usage (total size <span id="memory_size"></span> Mb) </p>
|
||||
<div id="memory_space"></div>
|
||||
<p class="card-text"> Database size: <span id="database_size"></span> </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,10 +74,7 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Mesures PM</h5>
|
||||
<p class="card-text">Particules Fines </p>
|
||||
<canvas id="sensorPMChart" width="400" height="200"></canvas>
|
||||
|
||||
|
||||
<canvas id="sensorPMChart" style="width: 100%; max-width: 600px; height: 200px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,6 +150,34 @@ window.onload = function() {
|
||||
console.error('AJAX request failed:', status, error);
|
||||
}
|
||||
});
|
||||
|
||||
//get database size
|
||||
$.ajax({
|
||||
url: 'launcher.php?type=database_size',
|
||||
dataType: 'json', // Specify that you expect a JSON response
|
||||
method: 'GET', // Use GET or POST depending on your needs
|
||||
success: function(response) {
|
||||
console.log(response);
|
||||
|
||||
if (response.size_megabytes !== undefined) {
|
||||
// Extract and format the size in MB
|
||||
const databaseSizeMB = response.size_megabytes + " MB";
|
||||
|
||||
// Update the HTML element with the database size
|
||||
const databaseSizeElement = document.getElementById("database_size");
|
||||
databaseSizeElement.textContent = databaseSizeMB;
|
||||
|
||||
console.log("Database size:", databaseSizeMB);
|
||||
} else if (response.error) {
|
||||
// Handle errors from the PHP response
|
||||
console.error("Error from server:", response.error);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('AJAX request failed:', status, error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//get disk free space
|
||||
$.ajax({
|
||||
@@ -289,7 +315,41 @@ window.onload = function() {
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Time'
|
||||
},
|
||||
ticks: {
|
||||
autoSkip: true,
|
||||
maxTicksLimit: 5,
|
||||
callback: function(value, index) {
|
||||
// Access the correct label from the `labels` array
|
||||
const label = labels[index]; // Use the original `labels` array
|
||||
if (label && typeof label === 'string' && label.includes(' ')) {
|
||||
return label.split(' ')[1].slice(0, 5); // Extract "HH:MM"
|
||||
}
|
||||
return value; // Fallback for invalid labels
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
y: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Values (µg/m³)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -13,8 +13,8 @@ if ($type == "get_npm_sqlite_data") {
|
||||
$db = new PDO("sqlite:$database_path");
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// Fetch the last 10 records
|
||||
$stmt = $db->query("SELECT timestamp, PM1, PM25, PM10 FROM data ORDER BY timestamp DESC LIMIT 10");
|
||||
// Fetch the last 30 records
|
||||
$stmt = $db->query("SELECT timestamp, PM1, PM25, PM10 FROM data ORDER BY timestamp DESC LIMIT 30");
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode($data);
|
||||
@@ -92,6 +92,57 @@ if ($type == "clear_loopLogs") {
|
||||
echo $output;
|
||||
}
|
||||
|
||||
if ($type == "database_size") {
|
||||
|
||||
// Path to the SQLite database file
|
||||
$databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db';
|
||||
|
||||
// Check if the file exists
|
||||
if (file_exists($databasePath)) {
|
||||
try {
|
||||
// Connect to the SQLite database
|
||||
$db = new PDO("sqlite:$databasePath");
|
||||
|
||||
// Get the file size in bytes
|
||||
$fileSizeBytes = filesize($databasePath);
|
||||
|
||||
// Convert the file size to human-readable formats
|
||||
$fileSizeKilobytes = $fileSizeBytes / 1024; // KB
|
||||
$fileSizeMegabytes = $fileSizeKilobytes / 1024; // MB
|
||||
|
||||
// Query the number of records in the `data` table
|
||||
$query = "SELECT COUNT(*) AS total_records FROM data";
|
||||
$result = $db->query($query);
|
||||
$recordCount = $result ? $result->fetch(PDO::FETCH_ASSOC)['total_records'] : 0;
|
||||
|
||||
// Prepare the JSON response
|
||||
$data = [
|
||||
'path' => $databasePath,
|
||||
'size_bytes' => $fileSizeBytes,
|
||||
'size_kilobytes' => round($fileSizeKilobytes, 2),
|
||||
'size_megabytes' => round($fileSizeMegabytes, 2),
|
||||
'data_table_records' => $recordCount
|
||||
];
|
||||
|
||||
// Output the JSON response
|
||||
echo json_encode($data, JSON_PRETTY_PRINT);
|
||||
} catch (PDOException $e) {
|
||||
// Handle database connection errors
|
||||
echo json_encode([
|
||||
'error' => 'Database query failed: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Handle error if the file doesn't exist
|
||||
echo json_encode([
|
||||
'error' => 'Database file not found',
|
||||
'path' => $databasePath
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ($type == "linux_disk") {
|
||||
$command = 'df -h /';
|
||||
$output = shell_exec($command);
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
</svg>
|
||||
Capteurs
|
||||
</a>
|
||||
<a class="nav-link text-white" href="database.html">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-database" viewBox="0 0 16 16">
|
||||
<path d="M4.318 2.687C5.234 2.271 6.536 2 8 2s2.766.27 3.682.687C12.644 3.125 13 3.627 13 4c0 .374-.356.875-1.318 1.313C10.766 5.729 9.464 6 8 6s-2.766-.27-3.682-.687C3.356 4.875 3 4.373 3 4c0-.374.356-.875 1.318-1.313M13 5.698V7c0 .374-.356.875-1.318 1.313C10.766 8.729 9.464 9 8 9s-2.766-.27-3.682-.687C3.356 7.875 3 7.373 3 7V5.698c.271.202.58.378.904.525C4.978 6.711 6.427 7 8 7s3.022-.289 4.096-.777A5 5 0 0 0 13 5.698M14 4c0-1.007-.875-1.755-1.904-2.223C11.022 1.289 9.573 1 8 1s-3.022.289-4.096.777C2.875 2.245 2 2.993 2 4v9c0 1.007.875 1.755 1.904 2.223C4.978 15.71 6.427 16 8 16s3.022-.289 4.096-.777C13.125 14.755 14 14.007 14 13zm-1 4.698V10c0 .374-.356.875-1.318 1.313C10.766 11.729 9.464 12 8 12s-2.766-.27-3.682-.687C3.356 10.875 3 10.373 3 10V8.698c.271.202.58.378.904.525C4.978 9.71 6.427 10 8 10s3.022-.289 4.096-.777A5 5 0 0 0 13 8.698m0 3V13c0 .374-.356.875-1.318 1.313C10.766 14.729 9.464 15 8 15s-2.766-.27-3.682-.687C3.356 13.875 3 13.373 3 13v-1.302c.271.202.58.378.904.525C4.978 12.71 6.427 13 8 13s3.022-.289 4.096-.777c.324-.147.633-.323.904-.525"/>
|
||||
</svg>
|
||||
|
||||
DataBase
|
||||
</a>
|
||||
<a class="nav-link text-white" href="saraR4.html">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-reception-4" viewBox="0 0 16 16">
|
||||
<path d="M0 11.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5zm4-3a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5zm4-3a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5zm4-3a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v11a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5z"/>
|
||||
|
||||
Reference in New Issue
Block a user