update
This commit is contained in:
@@ -52,9 +52,7 @@ def load_config(config_file):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Load the configuration data
|
# Load the configuration data
|
||||||
config_file = '/var/www/nebuleair_pro_4g/config.json'
|
npm_solo_port = "/dev/ttyAMA5" #port du NPM solo
|
||||||
config = load_config(config_file)
|
|
||||||
npm_solo_port = config.get('NPM_solo_port', '') #port du NPM solo
|
|
||||||
|
|
||||||
#GET RTC TIME from SQlite
|
#GET RTC TIME from SQlite
|
||||||
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
||||||
|
|||||||
@@ -28,31 +28,14 @@ cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
|
|||||||
row = cursor.fetchone() # Get the first (and only) row
|
row = cursor.fetchone() # Get the first (and only) row
|
||||||
rtc_time_str = row[1] # '2025-02-07 12:30:45'
|
rtc_time_str = row[1] # '2025-02-07 12:30:45'
|
||||||
|
|
||||||
# Function to load config data
|
# Fetch connected ENVEA sondes from SQLite config table
|
||||||
def load_config(config_file):
|
cursor.execute("SELECT port, name, coefficient FROM envea_sondes_table WHERE connected = 1")
|
||||||
try:
|
connected_envea_sondes = cursor.fetchall() # List of tuples (port, name, coefficient)
|
||||||
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 {}
|
|
||||||
|
|
||||||
# Define the config file path
|
|
||||||
config_file = '/var/www/nebuleair_pro_4g/config.json'
|
|
||||||
|
|
||||||
# Load the configuration data
|
|
||||||
config = load_config(config_file)
|
|
||||||
|
|
||||||
# Initialize sensors and serial connections
|
|
||||||
envea_sondes = config.get('envea_sondes', [])
|
|
||||||
connected_envea_sondes = [sonde for sonde in envea_sondes if sonde.get('connected', False)]
|
|
||||||
serial_connections = {}
|
serial_connections = {}
|
||||||
|
|
||||||
if connected_envea_sondes:
|
if connected_envea_sondes:
|
||||||
for device in connected_envea_sondes:
|
for port, name, coefficient in connected_envea_sondes:
|
||||||
port = device.get('port', 'Unknown')
|
|
||||||
name = device.get('name', 'Unknown')
|
|
||||||
try:
|
try:
|
||||||
serial_connections[name] = serial.Serial(
|
serial_connections[name] = serial.Serial(
|
||||||
port=f'/dev/{port}',
|
port=f'/dev/{port}',
|
||||||
@@ -74,9 +57,7 @@ data_nh3 = 0
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if connected_envea_sondes:
|
if connected_envea_sondes:
|
||||||
for device in connected_envea_sondes:
|
for port, name, coefficient in connected_envea_sondes:
|
||||||
name = device.get('name', 'Unknown')
|
|
||||||
coefficient = device.get('coefficient', 1)
|
|
||||||
if name in serial_connections:
|
if name in serial_connections:
|
||||||
serial_connection = serial_connections[name]
|
serial_connection = serial_connections[name]
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -114,10 +114,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="input-group mb-3" id="sondes_envea_div">
|
<div class="input-group mb-3" id="sondes_envea_div"></div>
|
||||||
|
|
||||||
|
<div id="envea_table"></div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!--<button type="submit" class="btn btn-primary">Submit</button>-->
|
<!--<button type="submit" class="btn btn-primary">Submit</button>-->
|
||||||
@@ -611,10 +610,18 @@ function add_sondeEnveaContainer() {
|
|||||||
|
|
||||||
// Create container div if it doesn't exist
|
// Create container div if it doesn't exist
|
||||||
if ($('#sondes_envea_div').length === 0) {
|
if ($('#sondes_envea_div').length === 0) {
|
||||||
$('#advanced_options').append('<div id="sondes_envea_div" class="input-group mt-4 border p-3 rounded"><legend>Sondes Envea</legend></div>');
|
$('#advanced_options').append('<div id="sondes_envea_div" class="input-group mt-4 border p-3 rounded"><legend>Sondes Envea</legend><p>Plouf</p></div>');
|
||||||
} else {
|
} else {
|
||||||
// Clear existing content if container exists
|
// Clear existing content if container exists
|
||||||
$('#sondes_envea_div').html('<legend>Sondes Envea</legend>');
|
$('#sondes_envea_div').html('<legend>Sondes Envea</legend>');
|
||||||
|
$('#envea_table').html('<table class="table table-striped table-bordered">'+
|
||||||
|
'<thead><tr><th scope="col">Software</th><th scope="col">Hardware (PCB)</th></tr></thead>'+
|
||||||
|
'<tbody>' +
|
||||||
|
'<tr><td>ttyAMA5</td><td>NPM1</td></tr>' +
|
||||||
|
'<tr><td>ttyAMA4</td><td>NPM2</td></tr>' +
|
||||||
|
'<tr><td>ttyAMA3</td><td>NPM3</td></tr>' +
|
||||||
|
'<tr><td>ttyAMA2</td><td>SARA</td></tr>' +
|
||||||
|
'</tbody></table>');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each sonde and create UI elements
|
// Loop through each sonde and create UI elements
|
||||||
|
|||||||
@@ -577,9 +577,9 @@ try:
|
|||||||
payload_csv[10] = averages[1] # envea_h2s
|
payload_csv[10] = averages[1] # envea_h2s
|
||||||
payload_csv[11] = averages[2] # envea_nh3
|
payload_csv[11] = averages[2] # envea_nh3
|
||||||
|
|
||||||
#Add data to payload JSON
|
#Add data to payload JSON
|
||||||
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NO2", "value": str(averages[0])})
|
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NO2", "value": str(averages[0])})
|
||||||
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NO2", "value": str(averages[1])})
|
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_H2S", "value": str(averages[1])})
|
||||||
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NH3", "value": str(averages[2])})
|
payload_json["sensordatavalues"].append({"value_type": "CAIRSENS_NH3", "value": str(averages[2])})
|
||||||
|
|
||||||
#Wind meter
|
#Wind meter
|
||||||
|
|||||||
104
master.py
104
master.py
@@ -52,17 +52,73 @@ Specific scripts can be disabled with config.json
|
|||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
|
||||||
# Base directory where scripts are stored
|
# Base directory where scripts are stored
|
||||||
SCRIPT_DIR = "/var/www/nebuleair_pro_4g/"
|
SCRIPT_DIR = "/var/www/nebuleair_pro_4g/"
|
||||||
CONFIG_FILE = "/var/www/nebuleair_pro_4g/config.json"
|
DB_PATH = "/var/www/nebuleair_pro_4g/sqlite/sensors.db"
|
||||||
|
|
||||||
|
# Lock file path for SARA script
|
||||||
|
SARA_LOCK_FILE = "/var/www/nebuleair_pro_4g/sara_script.lock"
|
||||||
|
|
||||||
|
|
||||||
|
def is_script_enabled(script_name):
|
||||||
|
"""Check if a script is enabled in the database."""
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT enabled FROM config_scripts_table WHERE script_path = ?",
|
||||||
|
(script_name,)
|
||||||
|
)
|
||||||
|
|
||||||
|
result = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return True # Default to enabled if not found in database
|
||||||
|
|
||||||
|
return bool(result[0])
|
||||||
|
except Exception:
|
||||||
|
# If any database error occurs, default to enabled
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def create_lock_file():
|
||||||
|
"""Create a lock file for the SARA script."""
|
||||||
|
with open(SARA_LOCK_FILE, 'w') as f:
|
||||||
|
f.write(str(int(time.time())))
|
||||||
|
|
||||||
|
|
||||||
|
def remove_lock_file():
|
||||||
|
"""Remove the SARA script lock file."""
|
||||||
|
if os.path.exists(SARA_LOCK_FILE):
|
||||||
|
os.remove(SARA_LOCK_FILE)
|
||||||
|
|
||||||
|
|
||||||
|
def is_script_locked():
|
||||||
|
"""Check if the SARA script is currently locked."""
|
||||||
|
if not os.path.exists(SARA_LOCK_FILE):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check if lock is older than 60 seconds (stale)
|
||||||
|
with open(SARA_LOCK_FILE, 'r') as f:
|
||||||
|
try:
|
||||||
|
lock_time = int(f.read().strip())
|
||||||
|
if time.time() - lock_time > 60:
|
||||||
|
# Lock is stale, remove it
|
||||||
|
remove_lock_file()
|
||||||
|
return False
|
||||||
|
except ValueError:
|
||||||
|
# Invalid lock file content
|
||||||
|
remove_lock_file()
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def load_config():
|
|
||||||
"""Load the configuration file to determine which scripts to run."""
|
|
||||||
with open(CONFIG_FILE, "r") as f:
|
|
||||||
return json.load(f)
|
|
||||||
|
|
||||||
def run_script(script_name, interval, delay=0):
|
def run_script(script_name, interval, delay=0):
|
||||||
"""Run a script in a synchronized loop with an optional start delay."""
|
"""Run a script in a synchronized loop with an optional start delay."""
|
||||||
@@ -70,33 +126,41 @@ def run_script(script_name, interval, delay=0):
|
|||||||
next_run = time.monotonic() + delay # Apply the initial delay
|
next_run = time.monotonic() + delay # Apply the initial delay
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
config = load_config()
|
if is_script_enabled(script_name):
|
||||||
if config.get(script_name, True): # Default to True if not found
|
# Special handling for SARA script to prevent concurrent runs
|
||||||
subprocess.run(["python3", script_path])
|
if script_name == "loop/SARA_send_data_v2.py":
|
||||||
|
if not is_script_locked():
|
||||||
|
create_lock_file()
|
||||||
|
try:
|
||||||
|
subprocess.run(["python3", script_path])
|
||||||
|
finally:
|
||||||
|
remove_lock_file()
|
||||||
|
else:
|
||||||
|
# Run other scripts normally
|
||||||
|
subprocess.run(["python3", script_path])
|
||||||
|
|
||||||
# Wait until the next exact interval
|
# Wait until the next exact interval
|
||||||
next_run += interval
|
next_run += interval
|
||||||
sleep_time = max(0, next_run - time.monotonic()) # Prevent negative sleep times
|
sleep_time = max(0, next_run - time.monotonic()) # Prevent negative sleep times
|
||||||
time.sleep(sleep_time)
|
time.sleep(sleep_time)
|
||||||
|
|
||||||
|
|
||||||
# Define scripts and their execution intervals (seconds)
|
# Define scripts and their execution intervals (seconds)
|
||||||
SCRIPTS = [
|
SCRIPTS = [
|
||||||
#("RTC/save_to_db.py", 1, 0), # --> will run as a separated system service (rtc_save_to_db.service)
|
# Format: (script_name, interval_in_seconds, start_delay_in_seconds)
|
||||||
("NPM/get_data_modbus_v3.py", 10, 0), # Get NPM data (modbus 5 channels) every 10s, with 2s delay
|
("NPM/get_data_modbus_v3.py", 10, 0), # Get NPM data (modbus 5 channels) every 10s
|
||||||
("envea/read_value_v2.py", 10, 0), # Get NPM data (modbus 5 channels) every 10s, with 2s delay
|
("envea/read_value_v2.py", 10, 0), # Get Envea data every 10s
|
||||||
("loop/SARA_send_data_v2.py", 60, 1), # Send data every 60 seconds, with 2s delay
|
("loop/SARA_send_data_v2.py", 60, 1), # Send data every 60 seconds, with 1s delay
|
||||||
("BME280/get_data_v2.py", 120, 0), # Get BME280 data every 120 seconds, no delay
|
("BME280/get_data_v2.py", 120, 0), # Get BME280 data every 120 seconds
|
||||||
("MPPT/read.py", 120, 0), # Get MPPT data every 120 seconds, no delay
|
("MPPT/read.py", 120, 0), # Get MPPT data every 120 seconds
|
||||||
#("windMeter/read.py", 60, 2), # --> will run as a separated system service ()
|
("sqlite/flush_old_data.py", 86400, 0) # Flush old data inside db every day
|
||||||
("sqlite/flush_old_data.py", 86400, 0) # flush old data inside db every day ()
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Start threads for enabled scripts
|
# Start threads for scripts
|
||||||
for script_name, interval, delay in SCRIPTS:
|
for script_name, interval, delay in SCRIPTS:
|
||||||
thread = threading.Thread(target=run_script, args=(script_name, interval, delay), daemon=True)
|
thread = threading.Thread(target=run_script, args=(script_name, interval, delay), daemon=True)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
# Keep the main script running
|
# Keep the main script running
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
Reference in New Issue
Block a user