diff --git a/html/database.html b/html/database.html
index 89e6ee2..dd63463 100755
--- a/html/database.html
+++ b/html/database.html
@@ -108,7 +108,24 @@
-
@@ -224,6 +240,9 @@ window.onload = function() {
}); //end ajax
+ // Get database table stats
+ loadDbStats();
+
//get local RTC
$.ajax({
url: 'launcher.php?type=RTC_time',
@@ -478,6 +497,67 @@ function downloadCSV(response, table) {
document.body.removeChild(a);
}
+// Table display names
+const tableDisplayNames = {
+ 'data_NPM': 'PM (NextPM)',
+ 'data_NPM_5channels': 'PM 5 canaux',
+ 'data_BME280': 'Temp/Hum (BME280)',
+ 'data_envea': 'Gaz (Cairsens)',
+ 'data_WIND': 'Vent',
+ 'data_MPPT': 'Batterie (MPPT)',
+ 'data_NOISE': 'Bruit'
+};
+
+function loadDbStats() {
+ $.ajax({
+ url: 'launcher.php?type=db_table_stats',
+ dataType: 'json',
+ method: 'GET',
+ success: function(response) {
+ if (!response.success) {
+ document.getElementById('db_stats_content').innerHTML =
+ '
' + (response.error || 'Erreur') + '
';
+ return;
+ }
+
+ let html = '
Taille totale: ' + response.size_mb + ' MB
';
+ html += '
';
+ html += '';
+ html += '| Table | ';
+ html += 'Entrées | ';
+ html += 'Plus ancienne | ';
+ html += 'Plus récente | ';
+ html += '
';
+
+ response.tables.forEach(function(t) {
+ const displayName = tableDisplayNames[t.name] || t.name;
+ const oldest = t.oldest ? t.oldest.substring(0, 16) : '-';
+ const newest = t.newest ? t.newest.substring(0, 16) : '-';
+ html += '';
+ html += '| ' + displayName + ' | ';
+ html += '' + t.count.toLocaleString() + ' | ';
+ html += '' + oldest + ' | ';
+ html += '' + newest + ' | ';
+ html += '
';
+ });
+
+ html += '
';
+ html += '
';
+
+ document.getElementById('db_stats_content').innerHTML = html;
+
+ // Re-apply translations if i18n is loaded
+ if (typeof i18n !== 'undefined' && i18n.translations && Object.keys(i18n.translations).length > 0) {
+ i18n.applyTranslations();
+ }
+ },
+ error: function(xhr, status, error) {
+ document.getElementById('db_stats_content').innerHTML =
+ '
Erreur: ' + error + '
';
+ }
+ });
+}
+
// Function to empty all sensor tables
function emptySensorTables() {
// Show confirmation dialog
diff --git a/html/lang/en.json b/html/lang/en.json
index 12dd96d..00b42c7 100644
--- a/html/lang/en.json
+++ b/html/lang/en.json
@@ -92,7 +92,13 @@
"dangerZone": "Danger Zone",
"dangerWarning": "Warning: This action is irreversible!",
"emptyAllTables": "Empty all sensor tables",
- "emptyTablesNote": "Note: Configuration and timestamp tables will be preserved."
+ "emptyTablesNote": "Note: Configuration and timestamp tables will be preserved.",
+ "statsTitle": "Database Information",
+ "statsDbSize": "Total size:",
+ "statsTable": "Table",
+ "statsCount": "Entries",
+ "statsOldest": "Oldest",
+ "statsNewest": "Newest"
},
"logs": {
"title": "The Log",
diff --git a/html/lang/fr.json b/html/lang/fr.json
index e48b065..bf7ebba 100644
--- a/html/lang/fr.json
+++ b/html/lang/fr.json
@@ -92,7 +92,13 @@
"dangerZone": "Zone dangereuse",
"dangerWarning": "Attention: Cette action est irréversible!",
"emptyAllTables": "Vider toutes les tables de capteurs",
- "emptyTablesNote": "Note: Les tables de configuration et horodatage seront préservées."
+ "emptyTablesNote": "Note: Les tables de configuration et horodatage seront préservées.",
+ "statsTitle": "Informations sur la base",
+ "statsDbSize": "Taille totale:",
+ "statsTable": "Table",
+ "statsCount": "Entrées",
+ "statsOldest": "Plus ancienne",
+ "statsNewest": "Plus récente"
},
"logs": {
"title": "Le journal",
diff --git a/html/launcher.php b/html/launcher.php
index c926a2f..74d80e0 100755
--- a/html/launcher.php
+++ b/html/launcher.php
@@ -530,6 +530,60 @@ if ($type == "database_size") {
}
+if ($type == "db_table_stats") {
+ $databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db';
+
+ if (file_exists($databasePath)) {
+ try {
+ $db = new PDO("sqlite:$databasePath");
+
+ // Database file size
+ $fileSizeBytes = filesize($databasePath);
+ $fileSizeMB = round($fileSizeBytes / (1024 * 1024), 2);
+
+ // Sensor data tables to inspect
+ $tables = ['data_NPM', 'data_NPM_5channels', 'data_BME280', 'data_envea', 'data_WIND', 'data_MPPT', 'data_NOISE'];
+
+ $tableStats = [];
+ foreach ($tables as $tableName) {
+ // Check if table exists
+ $check = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='$tableName'");
+ if ($check->fetch()) {
+ $countResult = $db->query("SELECT COUNT(*) as cnt FROM $tableName")->fetch();
+ $count = (int)$countResult['cnt'];
+
+ $oldest = null;
+ $newest = null;
+ if ($count > 0) {
+ $oldestResult = $db->query("SELECT MIN(timestamp) as ts FROM $tableName")->fetch();
+ $newestResult = $db->query("SELECT MAX(timestamp) as ts FROM $tableName")->fetch();
+ $oldest = $oldestResult['ts'];
+ $newest = $newestResult['ts'];
+ }
+
+ $tableStats[] = [
+ 'name' => $tableName,
+ 'count' => $count,
+ 'oldest' => $oldest,
+ 'newest' => $newest
+ ];
+ }
+ }
+
+ echo json_encode([
+ 'success' => true,
+ 'size_mb' => $fileSizeMB,
+ 'size_bytes' => $fileSizeBytes,
+ 'tables' => $tableStats
+ ]);
+ } catch (PDOException $e) {
+ echo json_encode(['success' => false, 'error' => 'Database query failed: ' . $e->getMessage()]);
+ }
+ } else {
+ echo json_encode(['success' => false, 'error' => 'Database file not found']);
+ }
+}
+
if ($type == "linux_disk") {
$command = 'df -h /';
$output = shell_exec($command);