This commit is contained in:
Your Name
2025-03-20 17:45:47 +01:00
parent 4d15076d4b
commit d5302f78ba
11 changed files with 313 additions and 55 deletions

View File

@@ -28,7 +28,7 @@ Line by line installation.
``` ```
sudo apt update 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 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 mkdir -p /var/www/.ssh
sudo ssh-keygen -t rsa -b 4096 -f /var/www/.ssh/id_rsa -N "" sudo ssh-keygen -t rsa -b 4096 -f /var/www/.ssh/id_rsa -N ""

View File

@@ -36,6 +36,51 @@ def load_config(config_file):
print(f"Error loading config file: {e}") print(f"Error loading config file: {e}")
return {} 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'<span style="color: red;font-weight: bold;">[ALERT] ⚠️{total_elapsed_time:.2f}s⚠</span>')
return response.decode('utf-8', errors='replace') # Return the full response if no target line is found
# Define the config file path # Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json' config_file = '/var/www/nebuleair_pro_4g/config.json'
# Load the configuration data # Load the configuration data
@@ -57,17 +102,11 @@ ser.write((command + '\r').encode('utf-8'))
try: try:
# Read lines until a timeout occurs response = read_complete_response(ser, wait_for_lines=["OK", "ERROR"],timeout=5, end_of_response_timeout=120, debug=True)
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 print('<p class="text-danger-emphasis">')
for line in response_lines: print(response)
print(line) print("</p>", end="")
except serial.SerialException as e: except serial.SerialException as e:
print(f"Error: {e}") print(f"Error: {e}")

View File

@@ -25,13 +25,18 @@ for i in {1..5}; do
sleep 1 sleep 1
done 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 # 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)}') serial_number=$(cat /proc/cpuinfo | grep Serial | awk '{print substr($3, length($3) - 7)}')
# Use jq to update the "deviceID" in the JSON file # 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" echo "id: $serial_number"
#get the SSH port for tunneling #get the SSH port for tunneling
SSH_TUNNEL_PORT=$(jq -r '.sshTunnel_port' "$JSON_FILE") SSH_TUNNEL_PORT=$(jq -r '.sshTunnel_port' "$JSON_FILE")

View File

@@ -55,28 +55,20 @@
<div class="row mb-3"> <div class="row mb-3">
<div class="col-lg-3 col-12"> <div class="col-lg-3 col-12">
<h3 class="mt-4">Parameters</h3> <h3 class="mt-4">Parameters (config)</h3>
<form> <form>
<!-- <div class="mb-3">
<label for="device_name" class="form-label">Device Name</label>
<div class="form-check form-switch mb-2"> <input type="text" class="form-control" id="device_name" onchange="update_config_sqlite('deviceName', this.value)">
<input class="form-check-input" type="checkbox" role="switch" id="flex_loop" onchange="update_config('loop_activation',this.checked)">
<label class="form-check-label" for="flex_loop">Loop activation</label>
</div> </div>
<div class="form-check form-switch mb-2"> <div class="mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="flex_loop_log" onchange="update_config('loop_log', this.checked)"> <label for="device_ID" class="form-label">Device ID</label>
<label class="form-check-label" for="flex_loop_log">Loop Logs</label> <input type="text" class="form-control" id="device_ID" disabled>
</div> </div>
<div class="form-check form-switch mb-2">
<input class="form-check-input" type="checkbox" role="switch" id="flex_start_log" onchange="update_config('boot_log', this.checked)">
<label class="form-check-label" for="flex_start_log">Boot Logs</label>
</div>
-->
<div class="form-check mb-3"> <div class="form-check mb-3">
<input class="form-check-input" type="checkbox" value="" id="check_NPM_5channels" onchange="update_config('NextPM_5channels', this.checked)"> <input class="form-check-input" type="checkbox" value="" id="check_NPM_5channels" onchange="update_config('NextPM_5channels', this.checked)">
<label class="form-check-label" for="check_NPM_5channels"> <label class="form-check-label" for="check_NPM_5channels">
@@ -98,15 +90,7 @@
</label> </label>
</div> </div>
<div class="mb-3">
<label for="device_name" class="form-label">Device Name</label>
<input type="text" class="form-control" id="device_name" onchange="update_config('deviceName', this.value)">
</div>
<div class="mb-3">
<label for="device_ID" class="form-label">Device ID</label>
<input type="text" class="form-control" id="device_ID" disabled>
</div>
<!--<button type="submit" class="btn btn-primary">Submit</button>--> <!--<button type="submit" class="btn btn-primary">Submit</button>-->
</form> </form>
@@ -117,13 +101,6 @@
<h3 class="mt-4">Clock</h3> <h3 class="mt-4">Clock</h3>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" value="" id="check_RTC" onchange="update_config('i2c_RTC', this.checked)">
<label class="form-check-label" for="check_RTC">
RTC module (DS3231)
</label>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="sys_local_time" class="form-label">System time (local)</label> <label for="sys_local_time" class="form-label">System time (local)</label>
<input type="text" class="form-control" id="sys_local_time" disabled> <input type="text" class="form-control" id="sys_local_time" disabled>
@@ -227,11 +204,6 @@ window.onload = function() {
const checkbox_envea = document.getElementById("check_envea"); const checkbox_envea = document.getElementById("check_envea");
checkbox_envea.checked = data["envea/read_value_v2.py"]; 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 //device name
const device_name = document.getElementById("device_name"); const device_name = document.getElementById("device_name");
device_name.value = data.deviceName; device_name.value = data.deviceName;
@@ -300,6 +272,22 @@ window.onload = function() {
.catch(error => console.error('Error loading config.json:', error)); .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&param='+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){ function update_config(param, value){
console.log("Updating ",param," : ", value); console.log("Updating ",param," : ", value);

View File

@@ -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") { if ($type == "update_config") {
echo "updating...."; echo "updating....";
$param=$_GET['param']; $param=$_GET['param'];
@@ -269,7 +330,7 @@ if ($type == "sara_connectNetwork") {
$timeout=$_GET['timeout']; $timeout=$_GET['timeout'];
$networkID=$_GET['networkID']; $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) // Convert `networkID` to an integer (or float if needed)
$networkID = is_numeric($networkID) ? (strpos($networkID, '.') !== false ? (float)$networkID : (int)$networkID) : 0; $networkID = is_numeric($networkID) ? (strpos($networkID, '.') !== false ? (float)$networkID : (int)$networkID) : 0;
#save to config.json #save to config.json
@@ -296,10 +357,10 @@ if ($type == "sara_connectNetwork") {
die("Error: Could not write to JSON file."); 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; $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout;
$output = shell_exec($command); $output = shell_exec($command);
echo $output; echo $output;

View File

@@ -23,7 +23,7 @@ fi
# Update and install necessary packages # Update and install necessary packages
info "Updating package list and installing 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 # Install Python libraries
info "Installing Python libraries..." info "Installing Python libraries..."

View File

@@ -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) envea_cairsens= config.get('envea/read_value_v2.py', False)
mppt_charger= config.get('MPPT/read.py', False) mppt_charger= config.get('MPPT/read.py', False)
wind_meter= config.get('windMeter/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 () send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot ()
reset_uSpot_url = False reset_uSpot_url = False
selected_networkID = int(config.get('SARA_R4_neworkID', 0)) selected_networkID = int(config.get('SARA_R4_neworkID', 0))

View File

@@ -18,6 +18,35 @@ import sqlite3
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor() 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 # Create a table timer
cursor.execute(""" cursor.execute("""
CREATE TABLE IF NOT EXISTS timestamp_table ( CREATE TABLE IF NOT EXISTS timestamp_table (

View File

@@ -36,7 +36,6 @@ cursor = conn.cursor()
#cursor.execute("SELECT * FROM timestamp_table") #cursor.execute("SELECT * FROM timestamp_table")
if table_name == "timestamp_table": if table_name == "timestamp_table":
cursor.execute("SELECT * FROM timestamp_table") cursor.execute("SELECT * FROM timestamp_table")
else: else:
query = f"SELECT * FROM {table_name} ORDER BY timestamp DESC LIMIT ?" query = f"SELECT * FROM {table_name} ORDER BY timestamp DESC LIMIT ?"
cursor.execute(query, (limit_num,)) cursor.execute(query, (limit_num,))

43
sqlite/read_config.py Normal file
View File

@@ -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()

95
sqlite/set_config.py Normal file
View File

@@ -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!")