From 2129d45ef653777ae91894de93699ed984d98eed Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 25 Mar 2025 14:55:50 +0100 Subject: [PATCH] update --- SARA/reboot/start.py | 99 ++++- boot_hotspot.sh | 18 +- html/admin.html | 336 ++++++++++++++++ html/launcher.php | 132 ++++++ html/sensors.html | 375 ++++++++++-------- loop/SARA_send_data_v2.py | 92 ++--- config.json.dist => old/config.json.dist | 0 .../install_software.yaml | 0 8 files changed, 812 insertions(+), 240 deletions(-) rename config.json.dist => old/config.json.dist (100%) mode change 100755 => 100644 rename install_software.yaml => old/install_software.yaml (100%) mode change 100755 => 100644 diff --git a/SARA/reboot/start.py b/SARA/reboot/start.py index 7655a7c..27e3e4c 100644 --- a/SARA/reboot/start.py +++ b/SARA/reboot/start.py @@ -17,15 +17,43 @@ import time import sys import json import re +import sqlite3 -#get data from config -def load_config(config_file): +# database connection +conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") +cursor = conn.cursor() + +#get config data from SQLite table +def load_config_sqlite(): + """ + Load configuration data from SQLite config table + + Returns: + dict: Configuration data with proper type conversion + """ try: - with open(config_file, 'r') as file: - config_data = json.load(file) + + # Query the config table + cursor.execute("SELECT key, value, type FROM config_table") + rows = cursor.fetchall() + + # Create config dictionary + config_data = {} + for key, value, type_name in rows: + # Convert value based on its type + if type_name == 'bool': + config_data[key] = value == '1' or value == 'true' + elif type_name == 'int': + config_data[key] = int(value) + elif type_name == 'float': + config_data[key] = float(value) + else: + config_data[key] = value + return config_data + except Exception as e: - print(f"Error loading config file: {e}") + print(f"Error loading config from SQLite: {e}") return {} #Fonction pour mettre à jour le JSON de configuration @@ -57,10 +85,55 @@ def update_json_key(file_path, key, value): except Exception as e: print(f"Error updating the JSON file: {e}") -# Define the config file path -config_file = '/var/www/nebuleair_pro_4g/config.json' -# Load the configuration data -config = load_config(config_file) + +def update_sqlite_config(key, value): + """ + Updates a specific key in the SQLite config_table with a new value. + + :param key: The key to update in the config_table. + :param value: The new value to assign to the key. + """ + try: + + # Check if the key exists and get its type + cursor.execute("SELECT type FROM config_table WHERE key = ?", (key,)) + result = cursor.fetchone() + + if result is None: + print(f"Key '{key}' not found in the config_table.") + conn.close() + return + + # Get the type of the value from the database + value_type = result[0] + + # Convert the value to the appropriate string representation based on its type + if value_type == 'bool': + # Convert Python boolean or string 'true'/'false' to '1'/'0' + if isinstance(value, bool): + str_value = '1' if value else '0' + else: + str_value = '1' if str(value).lower() in ('true', '1', 'yes', 'y') else '0' + elif value_type == 'int': + str_value = str(int(value)) + elif value_type == 'float': + str_value = str(float(value)) + else: + str_value = str(value) + + # Update the value in the database + cursor.execute("UPDATE config_table SET value = ? WHERE key = ?", (str_value, key)) + + # Commit the changes and close the connection + conn.commit() + + print(f"💾 Updated '{key}' to '{value}' in database.") + except Exception as e: + print(f"Error updating the SQLite database: {e}") + +#Load config +config = load_config_sqlite() +#config baudrate = config.get('SaraR4_baudrate', 115200) #baudrate du sara R4 device_id = config.get('deviceID', '').upper() #device ID en maj @@ -151,7 +224,7 @@ try: print("⚠️ Could not identify modem model") print(f"🔍 Model: {model}") - update_json_key(config_file, "modem_version", model) + update_sqlite_config("modem_version", model) time.sleep(1) ''' @@ -332,9 +405,9 @@ try: else: print("❌ Failed to extract coordinates.") - #update config.json - update_json_key(config_file, "latitude_raw", float(latitude)) - update_json_key(config_file, "longitude_raw", float(longitude)) + #update sqlite table + update_sqlite_config("latitude_raw", float(latitude)) + update_sqlite_config("longitude_raw", float(longitude)) time.sleep(1) diff --git a/boot_hotspot.sh b/boot_hotspot.sh index a75dba6..4bc85d8 100755 --- a/boot_hotspot.sh +++ b/boot_hotspot.sh @@ -2,6 +2,8 @@ # Script to check if wifi is connected and start hotspot if not # will also retreive unique RPi ID and store it to deviceID.txt +# script that starts at boot: +# @reboot /var/www/nebuleair_pro_4g/boot_hotspot.sh >> /var/www/nebuleair_pro_4g/logs/app.log 2>&1 OUTPUT_FILE="/var/www/nebuleair_pro_4g/wifi_list.csv" JSON_FILE="/var/www/nebuleair_pro_4g/config.json" @@ -30,8 +32,7 @@ done echo "getting RPI serial number" # Get the last 8 characters of the serial number and write to text file serial_number=$(cat /proc/cpuinfo | grep Serial | awk '{print substr($3, length($3) - 7)}') -# Use jq to update the "deviceID" in the JSON file -#jq --arg serial_number "$serial_number" '.deviceID = $serial_number' "$JSON_FILE" > temp.json && mv temp.json "$JSON_FILE" + # update Sqlite database echo "Updating SQLite database with device ID: $serial_number" sqlite3 /var/www/nebuleair_pro_4g/sqlite/sensors.db "UPDATE config_table SET value='$serial_number' WHERE key='deviceID';" @@ -39,8 +40,8 @@ sqlite3 /var/www/nebuleair_pro_4g/sqlite/sensors.db "UPDATE config_table SET val echo "id: $serial_number" -#get the SSH port for tunneling -SSH_TUNNEL_PORT=$(jq -r '.sshTunnel_port' "$JSON_FILE") +# Get SSH tunnel port from SQLite config_table +SSH_TUNNEL_PORT=$(sqlite3 /var/www/nebuleair_pro_4g/sqlite/sensors.db "SELECT value FROM config_table WHERE key='sshTunnel_port'") #need to wait for the network manager to be ready sleep 20 @@ -58,17 +59,16 @@ if [ "$STATE" == "30 (disconnected)" ]; then echo "Starting hotspot..." sudo nmcli device wifi hotspot ifname wlan0 ssid nebuleair_pro password nebuleaircfg - # Update JSON to reflect hotspot mode - jq --arg status "hotspot" '.WIFI_status = $status' "$JSON_FILE" > temp.json && mv temp.json "$JSON_FILE" - + # Update SQLite to reflect hotspot mode + sqlite3 /var/www/nebuleair_pro_4g/sqlite/sensors.db "UPDATE config_table SET value='hotspot' WHERE key='WIFI_status'" else echo "🛜Success: wlan0 is connected!🛜" CONN_SSID=$(nmcli -g GENERAL.CONNECTION device show wlan0) echo "Connection: $CONN_SSID" - #update config JSON file - jq --arg status "connected" '.WIFI_status = $status' "$JSON_FILE" > temp.json && mv temp.json "$JSON_FILE" + # Update SQLite to reflect hotspot mode + sqlite3 /var/www/nebuleair_pro_4g/sqlite/sensors.db "UPDATE config_table SET value='connected' WHERE key='WIFI_status'" sudo chmod 777 "$JSON_FILE" diff --git a/html/admin.html b/html/admin.html index b643767..a237e92 100755 --- a/html/admin.html +++ b/html/admin.html @@ -114,6 +114,10 @@ +
+ + +
@@ -212,6 +216,16 @@ //end document.addEventListener + +/* + ___ _ _ + / _ \ _ __ | | ___ __ _ __| | + | | | | '_ \| | / _ \ / _` |/ _` | + | |_| | | | | |__| (_) | (_| | (_| | + \___/|_| |_|_____\___/ \__,_|\__,_| + +*/ + window.onload = function() { //NEW way to get config (SQLite) @@ -267,6 +281,12 @@ window.onload = function() { checkbox_envea.checked = response["envea/read_value_v2.py"]; checkbox_solar.checked = response["MPPT/read.py"]; checkbox_wind.checked = response["windMeter/read.py"]; + + //si sonde envea is true + if (response["envea/read_value_v2.py"]) { + add_sondeEnveaContainer(); + + } }, error: function(xhr, status, error) { console.error('AJAX request failed:', status, error); @@ -368,6 +388,10 @@ window.onload = function() { } //end window.onload + + + + function update_config_sqlite(param, value){ console.log("Updating sqlite ",param," : ", value); @@ -445,6 +469,12 @@ function update_config_scripts_sqlite(param, value) { Value: ${response.enabled !== undefined ? response.enabled : value}
${response.message || ''} `; + + if (response.script_path == "envea/read_value_v2.py") { + console.log("envea sondes activated"); + add_sondeEnveaContainer(); + + } } else { // Error message toastLiveExample.classList.remove('text-bg-success'); @@ -558,6 +588,312 @@ function set_RTC_withBrowser(){ }); //end ajax } +/* + ____ _ _____ + / ___| ___ _ __ __| | ___ ___ | ____|_ ____ _____ __ _ + \___ \ / _ \| '_ \ / _` |/ _ \/ __| | _| | '_ \ \ / / _ \/ _` | + ___) | (_) | | | | (_| | __/\__ \ | |___| | | \ V / __/ (_| | + |____/ \___/|_| |_|\__,_|\___||___/ |_____|_| |_|\_/ \___|\__,_| + +*/ + +function add_sondeEnveaContainer() { + console.log("Sonde Envea is true: need to add container!"); + + // Getting envea_sondes_table data + $.ajax({ + url: 'launcher.php?type=get_envea_sondes_table_sqlite', + dataType: 'json', + method: 'GET', + success: function(sondes) { + console.log("Getting SQLite envea sondes table:"); + console.log(sondes); + + // Create container div if it doesn't exist + if ($('#sondes_envea_div').length === 0) { + $('#advanced_options').append('
Sondes Envea
'); + } else { + // Clear existing content if container exists + $('#sondes_envea_div').html('Sondes Envea'); + } + + // Loop through each sonde and create UI elements + sondes.forEach(function(sonde) { + // Create a unique ID for this sonde + const sondeId = `sonde_${sonde.id}`; + + // Create HTML for this sonde + const sondeHtml = ` +
+
+ +
+ + + +
+ `; + + // Append this sonde to the container + $('#sondes_envea_div').append(sondeHtml); + }); + }, + error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); + } + }); +} + +// Helper functions for updating sonde properties +function updateSondeStatus(id, connected) { + console.log(`Updating sonde ${id} connected status to: ${connected}`); + const toastLiveExample = document.getElementById('liveToast'); + const toastBody = toastLiveExample.querySelector('.toast-body'); + + $.ajax({ + url: `launcher.php?type=update_sonde&id=${id}&field=connected&value=${connected ? 1 : 0}`, + dataType: 'json', + method: 'GET', + cache: false, + success: function(response) { + console.log('Sonde status updated:', response); + + // Format the response for toast + let formattedMessage = ''; + + if (response.success) { + // Success message + toastLiveExample.classList.remove('text-bg-danger'); + toastLiveExample.classList.add('text-bg-success'); + + formattedMessage = ` + Success!
+ Sonde ID: ${response.id}
+ Connected: ${connected ? "Yes" : "No"}
+ ${response.message || ''} + `; + } else { + // Error message + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + + formattedMessage = ` + Error!
+ ${response.error || 'Unknown error'}
+ Sonde ID: ${id} + `; + } + + // Update and show toast + toastBody.innerHTML = formattedMessage; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + }, + error: function(xhr, status, error) { + console.error('Failed to update sonde status:', error); + + // Show error toast + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + toastBody.innerHTML = ` + Request Failed!
+ Error: ${error}
+ Sonde ID: ${id} + `; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + } + }); +} + +function updateSondeName(id, name) { + console.log(`Updating sonde ${id} name to: ${name}`); + const toastLiveExample = document.getElementById('liveToast'); + const toastBody = toastLiveExample.querySelector('.toast-body'); + + $.ajax({ + url: `launcher.php?type=update_sonde&id=${id}&field=name&value=${encodeURIComponent(name)}`, + dataType: 'json', + method: 'GET', + cache: false, + success: function(response) { + console.log('Sonde name updated:', response); + + // Format the response for toast + let formattedMessage = ''; + + if (response.success) { + // Success message + toastLiveExample.classList.remove('text-bg-danger'); + toastLiveExample.classList.add('text-bg-success'); + + formattedMessage = ` + Success!
+ Sonde ID: ${response.id}
+ Name: ${name}
+ ${response.message || ''} + `; + } else { + // Error message + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + + formattedMessage = ` + Error!
+ ${response.error || 'Unknown error'}
+ Sonde ID: ${id} + `; + } + + // Update and show toast + toastBody.innerHTML = formattedMessage; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + }, + error: function(xhr, status, error) { + console.error('Failed to update sonde name:', error); + + // Show error toast + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + toastBody.innerHTML = ` + Request Failed!
+ Error: ${error}
+ Sonde ID: ${id} + `; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + } + }); +} + +function updateSondePort(id, port) { + console.log(`Updating sonde ${id} port to: ${port}`); + const toastLiveExample = document.getElementById('liveToast'); + const toastBody = toastLiveExample.querySelector('.toast-body'); + + $.ajax({ + url: `launcher.php?type=update_sonde&id=${id}&field=port&value=${encodeURIComponent(port)}`, + dataType: 'json', + method: 'GET', + cache: false, + success: function(response) { + console.log('Sonde port updated:', response); + + // Format the response for toast + let formattedMessage = ''; + + if (response.success) { + // Success message + toastLiveExample.classList.remove('text-bg-danger'); + toastLiveExample.classList.add('text-bg-success'); + + formattedMessage = ` + Success!
+ Sonde ID: ${response.id}
+ Port: ${port}
+ ${response.message || ''} + `; + } else { + // Error message + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + + formattedMessage = ` + Error!
+ ${response.error || 'Unknown error'}
+ Sonde ID: ${id} + `; + } + + // Update and show toast + toastBody.innerHTML = formattedMessage; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + }, + error: function(xhr, status, error) { + console.error('Failed to update sonde port:', error); + + // Show error toast + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + toastBody.innerHTML = ` + Request Failed!
+ Error: ${error}
+ Sonde ID: ${id} + `; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + } + }); +} + +function updateSondeCoefficient(id, coefficient) { + console.log(`Updating sonde ${id} coefficient to: ${coefficient}`); + const toastLiveExample = document.getElementById('liveToast'); + const toastBody = toastLiveExample.querySelector('.toast-body'); + + $.ajax({ + url: `launcher.php?type=update_sonde&id=${id}&field=coefficient&value=${coefficient}`, + dataType: 'json', + method: 'GET', + cache: false, + success: function(response) { + console.log('Sonde coefficient updated:', response); + + // Format the response for toast + let formattedMessage = ''; + + if (response.success) { + // Success message + toastLiveExample.classList.remove('text-bg-danger'); + toastLiveExample.classList.add('text-bg-success'); + + formattedMessage = ` + Success!
+ Sonde ID: ${response.id}
+ Coefficient: ${coefficient}
+ ${response.message || ''} + `; + } else { + // Error message + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + + formattedMessage = ` + Error!
+ ${response.error || 'Unknown error'}
+ Sonde ID: ${id} + `; + } + + // Update and show toast + toastBody.innerHTML = formattedMessage; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + }, + error: function(xhr, status, error) { + console.error('Failed to update sonde coefficient:', error); + + // Show error toast + toastLiveExample.classList.remove('text-bg-success'); + toastLiveExample.classList.add('text-bg-danger'); + toastBody.innerHTML = ` + Request Failed!
+ Error: ${error}
+ Sonde ID: ${id} + `; + const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample); + toastBootstrap.show(); + } + }); +} + diff --git a/html/launcher.php b/html/launcher.php index ddb03d7..8008684 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -28,6 +28,9 @@ if ($type == "get_npm_sqlite_data") { } } +/* + +*/ //GETING data from config_table (SQLite DB) if ($type == "get_config_sqlite") { try { @@ -74,6 +77,9 @@ if ($type == "get_config_sqlite") { } } +/* + +*/ //GETING data from config_scrips_table (SQLite DB) if ($type == "get_config_scripts_sqlite") { @@ -107,6 +113,51 @@ if ($type == "get_config_scripts_sqlite") { } +/* + +*/ +//GETING data from envea_sondes_table (SQLite DB) +if ($type == "get_envea_sondes_table_sqlite") { + + try { + $db = new PDO("sqlite:$database_path"); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Get all entries from envea_sondes_table + $query = $db->query("SELECT id, connected, port, name, coefficient FROM envea_sondes_table"); + $data = $query->fetchAll(PDO::FETCH_ASSOC); + + // Convert data types appropriately + $result = []; + foreach ($data as $item) { + // Create object for each sonde with proper data types + $sonde = [ + 'id' => (int)$item['id'], + 'connected' => $item['connected'] == 1, // Convert to boolean + 'port' => $item['port'], + 'name' => $item['name'], + 'coefficient' => (float)$item['coefficient'] // Convert to float + ]; + + // Add to results array + $result[] = $sonde; + } + + + // Return JSON response + header('Content-Type: application/json'); + echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + + } catch (PDOException $e) { + // Return error as JSON + header('Content-Type: application/json'); + echo json_encode(['error' => 'Database error: ' . $e->getMessage()]); + } + +} + + + //UPDATING the config_table from SQLite DB if ($type == "update_config_sqlite") { @@ -214,6 +265,87 @@ if ($type == "update_config_scripts_sqlite") { } } +//UPDATING the envea_sondes_table table from SQLite DB +if ($type == "update_sonde") { + $id = $_GET['id'] ?? null; + $field = $_GET['field'] ?? null; + $value = $_GET['value'] ?? null; + + // Validate parameters + if ($id === null || $field === null || $value === null) { + echo json_encode([ + "success" => false, + "error" => "Missing required parameters (id, field, or value)" + ]); + exit; + } + + // Validate field name (whitelist approach for security) + $allowed_fields = ['connected', 'port', 'name', 'coefficient']; + if (!in_array($field, $allowed_fields)) { + echo json_encode([ + "success" => false, + "error" => "Invalid field name: " . $field + ]); + exit; + } + + try { + // Connect to the database + $db = new PDO("sqlite:$database_path"); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Check if the sonde exists + $checkStmt = $db->prepare("SELECT id FROM envea_sondes_table WHERE id = :id"); + $checkStmt->bindParam(':id', $id, PDO::PARAM_INT); + $checkStmt->execute(); + + if (!$checkStmt->fetch()) { + echo json_encode([ + "success" => false, + "error" => "Sonde with ID $id not found" + ]); + exit; + } + + // Process value based on field type + if ($field == 'connected') { + // Convert to integer (0 or 1) + $processedValue = filter_var($value, FILTER_VALIDATE_BOOLEAN) ? 1 : 0; + $paramType = PDO::PARAM_INT; + } else if ($field == 'coefficient') { + // Convert to float + $processedValue = floatval($value); + $paramType = PDO::PARAM_STR; // SQLite doesn't have PARAM_FLOAT + } else { + // For text fields (port, name) + $processedValue = $value; + $paramType = PDO::PARAM_STR; + } + + // Update the sonde record + $updateStmt = $db->prepare("UPDATE envea_sondes_table SET $field = :value WHERE id = :id"); + $updateStmt->bindParam(':value', $processedValue, $paramType); + $updateStmt->bindParam(':id', $id, PDO::PARAM_INT); + $updateStmt->execute(); + + // Return success response + echo json_encode([ + "success" => true, + "message" => "Sonde $id updated successfully", + "field" => $field, + "value" => $processedValue + ]); + + } catch (PDOException $e) { + // Return error as JSON + echo json_encode([ + "success" => false, + "error" => "Database error: " . $e->getMessage() + ]); + } +} + //update the config (old JSON updating) if ($type == "update_config") { echo "updating.... "; diff --git a/html/sensors.html b/html/sensors.html index dbcd3e9..9484850 100755 --- a/html/sensors.html +++ b/html/sensors.html @@ -144,40 +144,50 @@ function getNPM_values(port){ } function getENVEA_values(port, name){ - console.log("Data from Envea "+ name+" (port "+port+"):"); - $("#loading_envea"+name).show(); + console.log("Data from Envea " + name + " (port " + port + "):"); + $("#loading_envea" + name).show(); - $.ajax({ - url: 'launcher.php?type=envea&port='+port+'&name='+name, - 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); - const tableBody = document.getElementById("data-table-body_envea"+name); - tableBody.innerHTML = ""; + $.ajax({ + url: 'launcher.php?type=envea&port=' + port + '&name=' + name, + dataType: 'json', + method: 'GET', + success: function(response) { + console.log(response); + const tableBody = document.getElementById("data-table-body_envea" + name); + tableBody.innerHTML = ""; - $("#loading_envea"+name).hide(); - // Create an array of the desired keys - // Create an array of the desired keys - const keysToShow = [name]; - // Add only the specified elements to the table - keysToShow.forEach(key => { - if (response !== undefined) { // Check if the key exists in the response - const value = response; - $("#data-table-body_envea"+name).append(` - - ${key} - ${value} ppb - - `); - } - }); - }, - error: function(xhr, status, error) { - console.error('AJAX request failed:', status, error); - } + $("#loading_envea" + name).hide(); + + const keysToShow = [name]; + keysToShow.forEach(key => { + if (response !== undefined) { + const value = response; + $("#data-table-body_envea" + name).append(` + + ${key} + ${value} ppb + + `); + } }); + }, + error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); + const tableBody = document.getElementById("data-table-body_envea" + name); + $("#loading_envea" + name).hide(); + + tableBody.innerHTML = ` + + + ❌ Error: unable to get data from sensor.
+ ${status}: ${error} + + + `; } + }); +} + function getNoise_values(){ console.log("Data from I2C Noise Sensor:"); @@ -261,143 +271,190 @@ function getBME280_values(){ window.onload = function() { - fetch('../config.json') // Replace 'deviceID.txt' with 'config.json' - .then(response => response.json()) // Parse response as JSON - .then(data => { - //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; - }); + + //NEW way to get config (SQLite) +$.ajax({ + url: 'launcher.php?type=get_config_sqlite', + dataType:'json', + //dataType: 'json', // Specify that you expect a JSON response + method: 'GET', // Use GET or POST depending on your needs + success: function(response) { + console.log("Getting SQLite config table:"); + console.log(response); + + + //device name_side bar + const elements = document.querySelectorAll('.sideBar_sensorName'); + elements.forEach((element) => { + element.innerText = response.deviceName; + }); + + }, +error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); +} + });//end AJAX + + //getting config_scripts table + $.ajax({ + url: 'launcher.php?type=get_config_scripts_sqlite', + dataType:'json', + //dataType: 'json', // Specify that you expect a JSON response + method: 'GET', // Use GET or POST depending on your needs + success: function(response) { + console.log("Getting SQLite config scripts table:"); + console.log(response); + + const container = document.getElementById('card-container'); // Conteneur des cartes + + //creates NPM card + if (response["NPM/get_data_modbus_v3.py"]) { + const cardHTML = ` +
+
+
+ Port UART +
+
+
NextPM
+

Capteur particules fines.

+ +
+ + + +
+
+
+
`; + + container.innerHTML += cardHTML; // Add the I2C card if condition is met + } + + //creates i2c BME280 card + if (response["BME280/get_data_v2.py"]) { + const i2C_BME_HTML = ` +
+
+
+ Port I2C +
+
+
BME280 Temp/Hum sensor
+

Capteur température et humidité sur le port I2C.

+ +
+ + + +
+
+
+
`; + + container.innerHTML += i2C_BME_HTML; // Add the I2C card if condition is met + } + + //creates i2c sound card + if (response.i2C_sound) { + const i2C_HTML = ` +
+
+
+ Port I2C +
+
+
Decibel Meter
+

Capteur bruit sur le port I2C.

+ +
+ + + + + +
+
+
+
`; + + container.innerHTML += i2C_HTML; // Add the I2C card if condition is met + } + + //Si on a des SONDES ENVEA connectée il faut faire un deuxième call dans la table envea_sondes_table + //creates ENVEA cards + if (response["envea/read_value_v2.py"]) { + console.log("Need to display ENVEA sondes"); + //getting config_scripts table + $.ajax({ + url: 'launcher.php?type=get_envea_sondes_table_sqlite', + dataType:'json', + //dataType: 'json', // Specify that you expect a JSON response + method: 'GET', // Use GET or POST depending on your needs + success: function(sondes) { + console.log("Getting SQLite envea sondes table:"); + console.log(sondes); + const ENVEA_sensors = sondes.filter(sonde => sonde.connected); // Filter only connected sondes + + ENVEA_sensors.forEach((sensor, index) => { + const port = sensor.port; // Port from the sensor object + const name = sensor.name; // Port from the sensor object + const coefficient = sensor.coefficient; + const cardHTML = ` +
+
+
+ Port UART ${port.replace('ttyAMA', '')} +
+
+
Sonde Envea ${name}
+

Capteur gas.

+ + + + +
+
+
+
`; + container.innerHTML += cardHTML; // Ajouter la carte au conteneur + }); + + }, + error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); + } + });//end AJAX envea Sondes - //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); - } - }); + }//end if + - const container = document.getElementById('card-container'); // Conteneur des cartes - - //creates NPM cards - const NPM_ports = data.NextPM_ports; // Récupère les ports - NPM_ports.forEach((port, index) => { - const cardHTML = ` -
-
-
- Port UART ${port.replace('ttyAMA', '')} -
-
-
NextPM ${String.fromCharCode(65 + index)}
-

Capteur particules fines.

- - - - -
-
-
-
`; - container.innerHTML += cardHTML; // Ajouter la carte au conteneur - }); +}, + error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); + } + });//end AJAX (config_scripts) - //creates ENVEA cards - const ENVEA_sensors = data.envea_sondes.filter(sonde => sonde.connected); // Filter only connected sondes + //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; - ENVEA_sensors.forEach((sensor, index) => { - const port = sensor.port; // Port from the sensor object - const name = sensor.name; // Port from the sensor object - const coefficient = sensor.coefficient; - const cardHTML = ` -
-
-
- Port UART ${port.replace('ttyAMA', '')} -
-
-
Sonde Envea ${name}
-

Capteur gas.

- - - - -
-
-
-
`; - container.innerHTML += cardHTML; // Ajouter la carte au conteneur - }); + }, + error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); + } + }); - //creates i2c BME280 card - if (data["BME280/get_data_v2.py"]) { - const i2C_BME_HTML = ` -
-
-
- Port I2C -
-
-
BME280 Temp/Hum sensor
-

Capteur température et humidité sur le port I2C.

- -
- - - -
-
-
-
`; - - container.innerHTML += i2C_BME_HTML; // Add the I2C card if condition is met - } - - //creates i2c sound card - if (data.i2C_sound) { - const i2C_HTML = ` -
-
-
- Port I2C -
-
-
Decibel Meter
-

Capteur bruit sur le port I2C.

- -
- - - - - -
-
-
-
`; - - container.innerHTML += i2C_HTML; // Add the I2C card if condition is met - } - - }) - .catch(error => console.error('Error loading config.json:', error)); - } +} //end windows onload diff --git a/loop/SARA_send_data_v2.py b/loop/SARA_send_data_v2.py index 698817e..3104af7 100755 --- a/loop/SARA_send_data_v2.py +++ b/loop/SARA_send_data_v2.py @@ -165,16 +165,6 @@ def blink_led(pin, blink_count, delay=1): GPIO.output(pin, GPIO.LOW) # Ensure LED is off print(f"LED on GPIO {pin} turned OFF (cleanup avoided)") -#get data from config (from JSON file) -def load_config(config_file): - try: - with open(config_file, 'r') as file: - config_data = json.load(file) - return config_data - except Exception as e: - print(f"Error loading config file: {e}") - return {} - #get config data from SQLite table def load_config_sqlite(): """ @@ -208,60 +198,51 @@ def load_config_sqlite(): print(f"Error loading config from SQLite: {e}") return {} - - -#Fonction pour mettre à jour le JSON de configuration -def update_json_key(file_path, key, value): +def load_config_scripts_sqlite(): """ - Updates a specific key in a JSON file with a new value. - - :param file_path: Path to the JSON file. - :param key: The key to update in the JSON file. - :param value: The new value to assign to the key. + Load script configuration data from SQLite config_scripts_table + + Returns: + dict: Script paths as keys and enabled status as boolean values """ try: - # Load the existing data - with open(file_path, "r") as file: - data = json.load(file) + # Query the config_scripts_table + cursor.execute("SELECT script_path, enabled FROM config_scripts_table") + rows = cursor.fetchall() - # Check if the key exists in the JSON file - if key in data: - data[key] = value # Update the key with the new value - else: - print(f"Key '{key}' not found in the JSON file.") - return + # Create config dictionary with script paths as keys and enabled status as boolean values + scripts_config = {} + for script_path, enabled in rows: + # Convert integer enabled value (0/1) to boolean + scripts_config[script_path] = bool(enabled) - # Write the updated data back to the file - with open(file_path, "w") as file: - json.dump(data, file, indent=2) # Use indent for pretty printing + return scripts_config - print(f"💾updating '{key}' to '{value}'.") except Exception as e: - print(f"Error updating the JSON file: {e}") + print(f"Error loading scripts config from SQLite: {e}") + return {} -# Define the config file path -config_file = '/var/www/nebuleair_pro_4g/config.json' - -# Load the configuration data (JSON way) -config = load_config(config_file) +#Load config +config = load_config_sqlite() +#config +device_id = config.get('deviceID', 'unknown') +device_id = device_id.upper() +modem_config_mode = config.get('modem_config_mode', False) device_latitude_raw = config.get('latitude_raw', 0) device_longitude_raw = config.get('longitude_raw', 0) -baudrate = config.get('SaraR4_baudrate', 115200) #baudrate du sara R4 -device_id = config.get('deviceID', '').upper() #device ID en maj -bme_280_config = config.get('BME280/get_data_v2.py', False) #présence du BME280 -envea_cairsens= config.get('envea/read_value_v2.py', False) -mppt_charger= config.get('MPPT/read.py', False) -wind_meter= config.get('windMeter/read.py', False) +modem_version=config.get('modem_version', "") +Sara_baudrate = config.get('SaraR4_baudrate', 115200) +npm_5channel = config.get('NextPM_5channels', False) #5 canaux du NPM +selected_networkID = int(config.get('SARA_R4_neworkID', 0)) send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot () reset_uSpot_url = False -selected_networkID = int(config.get('SARA_R4_neworkID', 0)) -npm_5channel = config.get('NextPM_5channels', False) #5 canaux du NPM -modem_version=config.get('modem_version', "") -modem_config_mode = config.get('modem_config_mode', False) #modem 4G en mode configuration - -#Load config new way -config = load_config_sqlite() +#config_scripts +config_scripts = load_config_scripts_sqlite() +bme_280_config = config_scripts.get('BME280/get_data_v2.py', False) +envea_cairsens= config_scripts.get('envea/read_value_v2.py', False) +mppt_charger= config_scripts.get('MPPT/read.py', False) +wind_meter= config_scripts.get('windMeter/read.py', False) #update device id in the payload json payload_json["nebuleairid"] = device_id @@ -273,7 +254,7 @@ if modem_config_mode: ser_sara = serial.Serial( port='/dev/ttyAMA2', - baudrate=baudrate, #115200 ou 9600 + baudrate=Sara_baudrate, #115200 ou 9600 parity=serial.PARITY_NONE, #PARITY_NONE, PARITY_EVEN or PARITY_ODD stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, @@ -767,8 +748,6 @@ try: print('ATTENTION: CME ERROR') print("error:", lines[-1]) print("*****") - #update status - update_json_key(config_file, "SARA_R4_network_status", "disconnected") # Gestion de l'erreur spécifique if "No connection to phone" in lines[-1]: @@ -807,7 +786,6 @@ try: if len(parts) == 3 and parts[-1] == '0': # The third value indicates success print("*****") print('⛔ATTENTION: HTTP operation failed') - update_json_key(config_file, "SARA_R4_network_status", "disconnected") print("*****") print("Blink red LED") # Run LED blinking in a separate thread @@ -854,7 +832,6 @@ try: # 2.2 code 1 (✅✅HHTP / UUHTTPCR succeded✅✅) else: print('✅✅HTTP operation successful.') - update_json_key(config_file, "SARA_R4_network_status", "connected") print("Blink blue LED") led_thread = Thread(target=blink_led, args=(23, 5, 0.5)) led_thread.start() @@ -1118,7 +1095,6 @@ try: print("error:", lines[-1]) print("*****") #update status - #update_json_key(config_file, "SARA_R4_network_status", "disconnected") # Gestion de l'erreur spécifique if "No connection to phone" in lines[-1]: @@ -1144,7 +1120,6 @@ try: if len(parts) == 3 and parts[-1] == '0': # The third value indicates success print("*****") print('⛔ATTENTION: HTTP operation failed') - update_json_key(config_file, "SARA_R4_network_status", "disconnected") print("*****") print("Blink red LED") # Run LED blinking in a separate thread @@ -1184,7 +1159,6 @@ try: else: # Si la commande HTTP a réussi print('✅✅HTTP operation successful.') - update_json_key(config_file, "SARA_R4_network_status", "connected") print("Blink blue LED") led_thread = Thread(target=blink_led, args=(23, 5, 0.5)) led_thread.start() diff --git a/config.json.dist b/old/config.json.dist old mode 100755 new mode 100644 similarity index 100% rename from config.json.dist rename to old/config.json.dist diff --git a/install_software.yaml b/old/install_software.yaml old mode 100755 new mode 100644 similarity index 100% rename from install_software.yaml rename to old/install_software.yaml