diff --git a/html/database.html b/html/database.html index dd63463..958491b 100755 --- a/html/database.html +++ b/html/database.html @@ -527,17 +527,22 @@ function loadDbStats() { html += 'Entrées'; html += 'Plus ancienne'; html += 'Plus récente'; + html += 'CSV'; 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) : '-'; + const downloadBtn = t.count > 0 + ? '' + : '-'; html += ''; html += '' + displayName + ''; html += '' + t.count.toLocaleString() + ''; html += '' + oldest + ''; html += '' + newest + ''; + html += '' + downloadBtn + ''; html += ''; }); diff --git a/html/lang/en.json b/html/lang/en.json index 00b42c7..556043f 100644 --- a/html/lang/en.json +++ b/html/lang/en.json @@ -98,7 +98,8 @@ "statsTable": "Table", "statsCount": "Entries", "statsOldest": "Oldest", - "statsNewest": "Newest" + "statsNewest": "Newest", + "statsDownload": "CSV" }, "logs": { "title": "The Log", diff --git a/html/lang/fr.json b/html/lang/fr.json index bf7ebba..b910dc2 100644 --- a/html/lang/fr.json +++ b/html/lang/fr.json @@ -98,7 +98,8 @@ "statsTable": "Table", "statsCount": "Entrées", "statsOldest": "Plus ancienne", - "statsNewest": "Plus récente" + "statsNewest": "Plus récente", + "statsDownload": "CSV" }, "logs": { "title": "Le journal", diff --git a/html/launcher.php b/html/launcher.php index 74d80e0..df83e7c 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -584,6 +584,52 @@ if ($type == "db_table_stats") { } } +if ($type == "download_full_table") { + $databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db'; + $table = $_GET['table'] ?? ''; + + // Whitelist of allowed tables + $allowedTables = ['data_NPM', 'data_NPM_5channels', 'data_BME280', 'data_envea', 'data_WIND', 'data_MPPT', 'data_NOISE']; + + if (!in_array($table, $allowedTables)) { + header('Content-Type: application/json'); + echo json_encode(['error' => 'Invalid table name']); + exit; + } + + // CSV headers per table + $csvHeaders = [ + 'data_NPM' => 'TimestampUTC,PM1,PM2.5,PM10,Temperature_sensor,Humidity_sensor', + 'data_NPM_5channels' => 'TimestampUTC,PM_ch1,PM_ch2,PM_ch3,PM_ch4,PM_ch5', + 'data_BME280' => 'TimestampUTC,Temperature,Humidity,Pressure', + 'data_envea' => 'TimestampUTC,NO2,H2S,NH3,CO,O3,SO2', + 'data_WIND' => 'TimestampUTC,Wind_speed_kmh,Wind_direction_V', + 'data_MPPT' => 'TimestampUTC,Battery_voltage,Battery_current,Solar_voltage,Solar_power,Charger_status', + 'data_NOISE' => 'TimestampUTC,Current_LEQ,DB_A_value' + ]; + + try { + $db = new PDO("sqlite:$databasePath"); + $rows = $db->query("SELECT * FROM $table ORDER BY timestamp ASC")->fetchAll(PDO::FETCH_NUM); + + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename="' . $table . '_full.csv"'); + + $output = fopen('php://output', 'w'); + // Write header + fputcsv($output, explode(',', $csvHeaders[$table])); + // Write data rows + foreach ($rows as $row) { + fputcsv($output, $row); + } + fclose($output); + } catch (PDOException $e) { + header('Content-Type: application/json'); + echo json_encode(['error' => 'Database query failed: ' . $e->getMessage()]); + } + exit; +} + if ($type == "linux_disk") { $command = 'df -h /'; $output = shell_exec($command);