From d5302f78ba1937cac35db54b1089d67566a7963f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 20 Mar 2025 17:45:47 +0100 Subject: [PATCH] udpate --- README.md | 2 +- SARA/sara_connectNetwork.py | 61 +++++++++++++++++++----- boot_hotspot.sh | 9 +++- html/admin.html | 58 +++++++++------------- html/launcher.php | 67 ++++++++++++++++++++++++-- installation_part1.sh | 2 +- loop/SARA_send_data_v2.py | 1 - sqlite/create_db.py | 29 +++++++++++ sqlite/read.py | 1 - sqlite/read_config.py | 43 +++++++++++++++++ sqlite/set_config.py | 95 +++++++++++++++++++++++++++++++++++++ 11 files changed, 313 insertions(+), 55 deletions(-) create mode 100644 sqlite/read_config.py create mode 100644 sqlite/set_config.py diff --git a/README.md b/README.md index 7e4426c..ae66099 100755 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Line by line installation. ``` sudo apt update -sudo apt install git gh apache2 php php-sqlite3 python3 python3-pip jq autossh i2c-tools python3-smbus -y +sudo apt install git gh apache2 sqlite3 php php-sqlite3 python3 python3-pip jq autossh i2c-tools python3-smbus -y sudo pip3 install pyserial requests RPi.GPIO adafruit-circuitpython-bme280 crcmod psutil ntplib pytz gpiozero adafruit-circuitpython-ads1x15 numpy --break-system-packages sudo mkdir -p /var/www/.ssh sudo ssh-keygen -t rsa -b 4096 -f /var/www/.ssh/id_rsa -N "" diff --git a/SARA/sara_connectNetwork.py b/SARA/sara_connectNetwork.py index 96b9a8f..6342cca 100755 --- a/SARA/sara_connectNetwork.py +++ b/SARA/sara_connectNetwork.py @@ -36,6 +36,51 @@ def load_config(config_file): print(f"Error loading config file: {e}") return {} +def read_complete_response(serial_connection, timeout=2, end_of_response_timeout=2, wait_for_lines=None, debug=True): + ''' + Fonction très importante !!! + Reads the complete response from a serial connection and waits for specific lines. + ''' + if wait_for_lines is None: + wait_for_lines = [] # Default to an empty list if not provided + + response = bytearray() + serial_connection.timeout = timeout + end_time = time.time() + end_of_response_timeout + start_time = time.time() + + while True: + elapsed_time = time.time() - start_time # Time since function start + if serial_connection.in_waiting > 0: + data = serial_connection.read(serial_connection.in_waiting) + response.extend(data) + end_time = time.time() + end_of_response_timeout # Reset timeout on new data + + # Decode and check for any target line + decoded_response = response.decode('utf-8', errors='replace') + for target_line in wait_for_lines: + if target_line in decoded_response: + if debug: + print(f"[DEBUG] 🔎 Found target line: {target_line} (in {elapsed_time:.2f}s)") + return decoded_response # Return response immediately if a target line is found + elif time.time() > end_time: + if debug: + print(f"[DEBUG] Timeout reached. No more data received.") + break + time.sleep(0.1) # Short sleep to prevent busy waiting + + # Final response and debug output + total_elapsed_time = time.time() - start_time + if debug: + print(f"[DEBUG] ⏱️ elapsed time: {total_elapsed_time:.2f}s. ⏱️") + # Check if the elapsed time exceeded 10 seconds + if total_elapsed_time > 10 and debug: + print(f"[ALERT] 🚨 The operation took too long 🚨") + print(f'[ALERT] ⚠️{total_elapsed_time:.2f}s⚠️') + + return response.decode('utf-8', errors='replace') # Return the full response if no target line is found + + # Define the config file path config_file = '/var/www/nebuleair_pro_4g/config.json' # Load the configuration data @@ -57,17 +102,11 @@ ser.write((command + '\r').encode('utf-8')) try: - # Read lines until a timeout occurs - response_lines = [] - while True: - line = ser.readline().decode('utf-8').strip() - if not line: - break # Break the loop if an empty line is encountered - response_lines.append(line) - - # Print the response - for line in response_lines: - print(line) + response = read_complete_response(ser, wait_for_lines=["OK", "ERROR"],timeout=5, end_of_response_timeout=120, debug=True) + + print('

') + print(response) + print("

", end="") except serial.SerialException as e: print(f"Error: {e}") diff --git a/boot_hotspot.sh b/boot_hotspot.sh index 8dac2f8..e616d81 100755 --- a/boot_hotspot.sh +++ b/boot_hotspot.sh @@ -25,13 +25,18 @@ for i in {1..5}; do sleep 1 done -echo "getting SARA R4 serial number" +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" +#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';" + echo "id: $serial_number" + #get the SSH port for tunneling SSH_TUNNEL_PORT=$(jq -r '.sshTunnel_port' "$JSON_FILE") diff --git a/html/admin.html b/html/admin.html index 8f5ef6b..c4ce27c 100755 --- a/html/admin.html +++ b/html/admin.html @@ -55,28 +55,20 @@
-

Parameters

+

Parameters (config)

- -
-
- - -
-
- - -
@@ -117,13 +101,6 @@

Clock

-
- - -
-
@@ -227,11 +204,6 @@ window.onload = function() { const checkbox_envea = document.getElementById("check_envea"); checkbox_envea.checked = data["envea/read_value_v2.py"]; - //get RTC check - const checkbox_RTC = document.getElementById("check_RTC"); - checkbox_RTC.checked = data.i2c_RTC; - - //device name const device_name = document.getElementById("device_name"); device_name.value = data.deviceName; @@ -300,6 +272,22 @@ window.onload = function() { .catch(error => console.error('Error loading config.json:', error)); } +function update_config_sqlite(param, value){ + console.log("Updating sqlite ",param," : ", value); + $.ajax({ + url: 'launcher.php?type=update_config_sqlite¶m='+param+'&value='+value, + dataType: 'text', // Specify that you expect a JSON response + method: 'GET', // Use GET or POST depending on your needs + cache: false, // Prevent AJAX from caching + success: function(response) { + console.log(response); + }, + error: function(xhr, status, error) { + console.error('AJAX request failed:', status, error); + } + }); +} + function update_config(param, value){ console.log("Updating ",param," : ", value); diff --git a/html/launcher.php b/html/launcher.php index bb60cbe..03afc46 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -25,6 +25,67 @@ if ($type == "get_npm_sqlite_data") { } } +if ($type == "update_config_sqlite") { + echo "updating...."; + $param = $_GET['param'] ?? null; + $value = $_GET['value'] ?? null; + + if ($param === null || $value === null) { + echo json_encode(["error" => "Missing parameter or value"]); + exit; + } + + $database_path = "/var/www/nebuleair_pro_4g/sqlite/sensors.db"; + try { + $db = new PDO("sqlite:$database_path"); + $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // First, check if parameter exists and get its type + $checkStmt = $db->prepare("SELECT type FROM config_table WHERE key = :param"); + $checkStmt->bindParam(':param', $param); + $checkStmt->execute(); + $result = $checkStmt->fetch(PDO::FETCH_ASSOC); + + if ($result) { + // Parameter exists, determine type and update + $type = $result['type']; + + // Convert value according to type if needed + $convertedValue = $value; + if ($type == "bool") { + // Convert various boolean representations to 0/1 + $convertedValue = (filter_var($value, FILTER_VALIDATE_BOOLEAN)) ? "1" : "0"; + } elseif ($type == "int") { + $convertedValue = (string)intval($value); + } elseif ($type == "float") { + $convertedValue = (string)floatval($value); + } + + // Update the value + $updateStmt = $db->prepare("UPDATE config_table SET value = :value WHERE key = :param"); + $updateStmt->bindParam(':value', $convertedValue); + $updateStmt->bindParam(':param', $param); + $updateStmt->execute(); + + echo json_encode([ + "success" => true, + "message" => "Configuration updated successfully", + "param" => $param, + "value" => $convertedValue, + "type" => $type + ]); + } else { + echo json_encode([ + "error" => "Parameter not found in configuration", + "param" => $param + ]); + } + } catch (PDOException $e) { + echo json_encode(["error" => $e->getMessage()]); + } +} + + if ($type == "update_config") { echo "updating...."; $param=$_GET['param']; @@ -269,7 +330,7 @@ if ($type == "sara_connectNetwork") { $timeout=$_GET['timeout']; $networkID=$_GET['networkID']; - echo "updating SARA_R4_networkID in config file"; + //echo "updating SARA_R4_networkID in config file"; // Convert `networkID` to an integer (or float if needed) $networkID = is_numeric($networkID) ? (strpos($networkID, '.') !== false ? (float)$networkID : (int)$networkID) : 0; #save to config.json @@ -296,10 +357,10 @@ if ($type == "sara_connectNetwork") { die("Error: Could not write to JSON file."); } - echo "SARA_R4_networkID updated successfully."; + //echo "SARA_R4_networkID updated successfully."; - echo "connecting to network... please wait..."; + //echo "connecting to network... please wait..."; $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout; $output = shell_exec($command); echo $output; diff --git a/installation_part1.sh b/installation_part1.sh index 8935d60..400912a 100644 --- a/installation_part1.sh +++ b/installation_part1.sh @@ -23,7 +23,7 @@ fi # Update and install necessary packages info "Updating package list and installing necessary packages..." -sudo apt update && sudo apt install -y git gh apache2 php php-sqlite3 python3 python3-pip jq autossh i2c-tools python3-smbus || error "Failed to install required packages." +sudo apt update && sudo apt install -y git gh apache2 sqlite3 php php-sqlite3 python3 python3-pip jq autossh i2c-tools python3-smbus || error "Failed to install required packages." # Install Python libraries info "Installing Python libraries..." diff --git a/loop/SARA_send_data_v2.py b/loop/SARA_send_data_v2.py index b5a5a19..29f677b 100755 --- a/loop/SARA_send_data_v2.py +++ b/loop/SARA_send_data_v2.py @@ -217,7 +217,6 @@ bme_280_config = config.get('BME280/get_data_v2.py', False) #présence d 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) -send_aircarto = config.get('send_aircarto', True) #envoi sur AirCarto (data.nebuleair.fr) send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot () reset_uSpot_url = False selected_networkID = int(config.get('SARA_R4_neworkID', 0)) diff --git a/sqlite/create_db.py b/sqlite/create_db.py index 22b8553..0b430ec 100755 --- a/sqlite/create_db.py +++ b/sqlite/create_db.py @@ -18,6 +18,35 @@ import sqlite3 conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") cursor = conn.cursor() +#create a config table +cursor.execute(""" +CREATE TABLE IF NOT EXISTS config_table ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL, + type TEXT NOT NULL +) +""") + +#creates a config_scripts table +cursor.execute(''' +CREATE TABLE IF NOT EXISTS config_scripts_table ( + script_path TEXT PRIMARY KEY, + enabled INTEGER NOT NULL +) +''') + +#creates a config table for envea sondes +cursor.execute(""" +CREATE TABLE IF NOT EXISTS envea_sondes_table ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + connected INTEGER NOT NULL, + port TEXT NOT NULL, + name TEXT NOT NULL, + coefficient REAL NOT NULL +) +""") + + # Create a table timer cursor.execute(""" CREATE TABLE IF NOT EXISTS timestamp_table ( diff --git a/sqlite/read.py b/sqlite/read.py index e75713b..c5a47ea 100755 --- a/sqlite/read.py +++ b/sqlite/read.py @@ -36,7 +36,6 @@ cursor = conn.cursor() #cursor.execute("SELECT * FROM timestamp_table") if table_name == "timestamp_table": cursor.execute("SELECT * FROM timestamp_table") - else: query = f"SELECT * FROM {table_name} ORDER BY timestamp DESC LIMIT ?" cursor.execute(query, (limit_num,)) diff --git a/sqlite/read_config.py b/sqlite/read_config.py new file mode 100644 index 0000000..bc7b2b7 --- /dev/null +++ b/sqlite/read_config.py @@ -0,0 +1,43 @@ +''' + ____ ___ _ _ _ + / ___| / _ \| | (_) |_ ___ + \___ \| | | | | | | __/ _ \ + ___) | |_| | |___| | || __/ + |____/ \__\_\_____|_|\__\___| + +Script to read data from a sqlite database +/usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/read_config.py config_table + +Available table are +config_table +config_scripts_table +envea_sondes_table + +''' + +import sqlite3 +import sys +parameter = sys.argv[1:] # Exclude the script name +#print("Parameters received:") +table_name=parameter[0] + + +# Connect to the SQLite database +conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") +cursor = conn.cursor() + +# Retrieve the data +query = f"SELECT * FROM {table_name}" +cursor.execute(query) + + +rows = cursor.fetchall() +rows.reverse() # Reverse the order in Python (to get ascending order) + + +# Display the results +for row in rows: + print(row) + +# Close the database connection +conn.close() diff --git a/sqlite/set_config.py b/sqlite/set_config.py new file mode 100644 index 0000000..2a9460c --- /dev/null +++ b/sqlite/set_config.py @@ -0,0 +1,95 @@ +''' + ____ ___ _ _ _ + / ___| / _ \| | (_) |_ ___ + \___ \| | | | | | | __/ _ \ + ___) | |_| | |___| | || __/ + |____/ \__\_\_____|_|\__\___| + +Script to set the config +/usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/set_config.py + +in case of readonly error: +sudo chmod 777 /var/www/nebuleair_pro_4g/sqlite/sensors.db +''' + +import sqlite3 + +# Connect to (or create if not existent) the database +conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") +cursor = conn.cursor() + +print(f"Connected to database") + +# Clear existing data (if any) +cursor.execute("DELETE FROM config_table") +cursor.execute("DELETE FROM config_scripts_table") +cursor.execute("DELETE FROM envea_sondes_table") +print("Existing data cleared") + +#add values + +# Insert script configurations +script_configs = [ + ("NPM/get_data_modbus_v3.py", True), + ("loop/SARA_send_data_v2.py", True), + ("RTC/save_to_db.py", True), + ("BME280/get_data_v2.py", True), + ("envea/read_value_v2.py", False), + ("MPPT/read.py", False), + ("windMeter/read.py", False), + ("sqlite/flush_old_data.py", True) +] + +for script_path, enabled in script_configs: + cursor.execute( + "INSERT INTO config_scripts_table (script_path, enabled) VALUES (?, ?)", + (script_path, 1 if enabled else 0) + ) + +# Insert general configurations +config_entries = [ + ("modem_config_mode", "0", "bool"), + ("deviceID", "XXXX", "str"), + ("npm_5channel", "0", "bool"), + ("latitude_raw", "0", "int"), + ("longitude_raw", "0", "int"), + ("latitude_precision", "0", "int"), + ("longitude_precision", "0", "int"), + ("deviceName", "NebuleAir-proXXX", "str"), + ("SaraR4_baudrate", "115200", "int"), + ("NPM_solo_port", "/dev/ttyAMA5", "str"), + ("sshTunnel_port", "59228", "int"), + ("SARA_R4_general_status", "connected", "str"), + ("SARA_R4_SIM_status", "connected", "str"), + ("SARA_R4_network_status", "connected", "str"), + ("SARA_R4_neworkID", "20810", "int"), + ("WIFI_status", "connected", "str"), + ("send_uSpot", "0", "bool"), + ("modem_version", "XXX", "str") +] + +for key, value, value_type in config_entries: + cursor.execute( + "INSERT INTO config_table (key, value, type) VALUES (?, ?, ?)", + (key, value, value_type) + ) + +# Insert envea sondes +envea_sondes = [ + (False, "ttyAMA4", "h2s", 4), + (False, "ttyAMA3", "no2", 1), + (False, "ttyAMA2", "o3", 1) +] + +for connected, port, name, coefficient in envea_sondes: + cursor.execute( + "INSERT INTO envea_sondes_table (connected, port, name, coefficient) VALUES (?, ?, ?, ?)", + (1 if connected else 0, port, name, coefficient) + ) + + +# Commit and close the connection +conn.commit() +conn.close() + +print("Database updated successfully!")