This commit is contained in:
Your Name
2025-02-20 15:30:34 +01:00
parent d5f1acc025
commit 725ee971c7
38 changed files with 405 additions and 84 deletions

7
.gitignore vendored
View File

@@ -1,5 +1,4 @@
logs/app.log
logs/loop.log
logs/*.log
deviceID.txt
loop/loop.log
loop/data.json
@@ -8,3 +7,7 @@ config.json
matrix/input.txt
matrix/input_NPM.txt
matrix/input_MHZ16.txt
wifi_list.csv
*.lock
sqlite/*.db
tests/

View File

@@ -1,4 +1,10 @@
'''
____ ___ ____
/ ___/ _ \___ \
| | | | | |__) |
| |__| |_| / __/
\____\___/_____|
Script to get CO2 values
need parameter: CO2_port
/usr/bin/python3 /var/www/moduleair_pro_4g/MH-Z19/get_data.py ttyAMA4

View File

@@ -1,4 +1,10 @@
'''
____ ___ ____
/ ___/ _ \___ \
| | | | | |__) |
| |__| |_| / __/
\____\___/_____|
Script to get CO2 values and write it to text file
need parameter: CO2_port
/usr/bin/python3 /var/www/moduleair_pro_4g/MH-Z19/write_data.py ttyAMA4

View File

@@ -1,7 +1,7 @@
'''
Script to get NPM firmware version
need parameter: port
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/firmware_version.py ttyAMA5
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/firmware_version.py ttyAMA5
'''
import serial

View File

@@ -7,7 +7,7 @@
Script to get NPM values
need parameter: port
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data.py ttyAMA5
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data.py ttyAMA5
'''
import serial

View File

@@ -7,7 +7,7 @@
Script to get NPM data via Modbus
need parameter: port
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus.py
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data_modbus.py
Modbus RTU
[Slave Address][Function Code][Starting Address][Quantity of Registers][CRC]

View File

@@ -7,7 +7,7 @@
Script to get NPM data via Modbus
need parameter: port
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_v2.py
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data_modbus_v2.py
Modbus RTU
[Slave Address][Function Code][Starting Address][Quantity of Registers][CRC]

View File

@@ -9,7 +9,7 @@ Script to get NPM data via Modbus
Improved version with data stream lenght check
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_v3.py
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data_modbus_v3.py
Modbus RTU
[Slave Address][Function Code][Starting Address][Quantity of Registers][CRC]

View File

@@ -7,7 +7,7 @@
Script to get NPM values: ONLY temp and hum
need parameter: port
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_temp_hum.py ttyAMA5
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data_temp_hum.py ttyAMA5
'''
import serial

View File

@@ -9,7 +9,7 @@ Script to get NPM values (PM1, PM2.5 and PM10)
PM and the sensor temp/hum
And store them inside sqlite database
Uses RTC module for timing (from SQLite db)
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_v2.py
/usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data_v2.py
'''
import serial

View File

@@ -1,6 +1,6 @@
'''
Check if the main loop is running
/usr/bin/python3 /var/www/nebuleair_pro_4g/tests/check_running.py
/usr/bin/python3 /var/www/moduleair_pro_4g/tests/check_running.py
'''
import psutil
import json
@@ -12,7 +12,7 @@ def is_script_running(script_name):
return True # Script is running
return False # Script is not running
script_to_check = "/var/www/nebuleair_pro_4g/loop/SARA_send_data_v2.py"
script_to_check = "/var/www/moduleair_pro_4g/loop/SARA_send_data_v2.py"
# Determine script status
is_running = is_script_running(script_to_check)

View File

@@ -1,13 +1,13 @@
'''
Script to see if the SARA-R410 is running
ex:
python3 /var/www/nebuleair_pro_4g/SARA/sara.py ttyAMA2 AT+CCID? 2
python3 /var/www/moduleair_pro_4g/SARA/sara.py ttyAMA2 AT+CCID? 2
ex 2 (turn on blue light):
python3 /var/www/nebuleair_pro_4g/SARA/sara.py ttyAMA2 AT+UGPIOC=16,2 2
python3 /var/www/moduleair_pro_4g/SARA/sara.py ttyAMA2 AT+UGPIOC=16,2 2
ex 3 (reconnect network)
python3 /var/www/nebuleair_pro_4g/SARA/sara.py ttyAMA2 AT+COPS=1,2,20801 20
python3 /var/www/moduleair_pro_4g/SARA/sara.py ttyAMA2 AT+COPS=1,2,20801 20
ex 4 (get HTTP Profiles)
python3 /var/www/nebuleair_pro_4g/SARA/sara.py ttyAMA2 AT+UHTTP? 2
python3 /var/www/moduleair_pro_4g/SARA/sara.py ttyAMA2 AT+UHTTP? 2
'''
@@ -33,7 +33,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -1,6 +1,6 @@
'''
Script to connect SARA-R410 to network SARA-R410
python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ttyAMA2 20801 10
python3 /var/www/moduleair_pro_4g/SARA/sara_connectNetwork.py ttyAMA2 20801 10
AT+COPS=1,2,20801
mode->1 pour manual
@@ -30,7 +30,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -22,7 +22,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -22,7 +22,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -23,7 +23,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -2,7 +2,7 @@
Script to connect SARA-R410 to APN
AT+CGDCONT=1,"IP","data.mono"
/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setAPN.py ttyAMA2 data.mono 2
/usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_setAPN.py ttyAMA2 data.mono 2
'''
import serial
@@ -27,7 +27,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -1,11 +1,11 @@
'''
Script to set the URL for a HTTP request
Ex:
/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ttyAMA2 data.nebuleair.fr 0
/usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_setURL.py ttyAMA2 data.moduleair.fr 0
To do: need to add profile id as parameter
First profile id:
AT+UHTTP=0,1,"data.nebuleair.fr"
AT+UHTTP=0,1,"data.moduleair.fr"
Second profile id:
AT+UHTTP=1,1,"api-prod.uspot.probesys.net"
'''
@@ -33,7 +33,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -1,11 +1,11 @@
'''
Script to set the URL for a HTTP request
Ex:
/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL_uSpot_noSSL.py ttyAMA2 api-prod.uspot.probesys.net
/usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_setURL_uSpot_noSSL.py ttyAMA2 api-prod.uspot.probesys.net
To do: need to add profile id as parameter
First profile id:
AT+UHTTP=0,1,"data.nebuleair.fr"
AT+UHTTP=0,1,"data.moduleair.fr"
Second profile id:
AT+UHTTP=1,1,"api-prod.uspot.probesys.net"
'''
@@ -51,7 +51,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -22,7 +22,7 @@ def load_config(config_file):
return {}
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
# Access the shared variables

View File

@@ -1,8 +1,14 @@
{
"loop_log": true,
"boot_log": true,
"modem_config_mode": false,
"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": true,
"sqlite/flush_old_data.py": true,
"deviceID": "XXXXX",
"SaraR4_baudrate": 115200,
"NPM_solo_port": "/dev/ttyAMA3",
"NextPM_ports": ["ttyAMA3"],
"CO2_serial": true,
"sensirion_SFA30": false,

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<script src="assets/js/chart.js"></script> <!-- Local Chart.js -->

View File

@@ -7,7 +7,7 @@ header("Pragma: no-cache");
$type=$_GET['type'];
if ($type == "get_npm_sqlite_data") {
$database_path = "/var/www/nebuleair_pro_4g/sqlite/sensors.db";
$database_path = "/var/www/moduleair_pro_4g/sqlite/sensors.db";
//echo "Getting data from sqlite database";
try {
$db = new PDO("sqlite:$database_path");
@@ -45,7 +45,7 @@ if ($type == "update_config") {
}
if ($type == "getModem_busy") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/check_running.py';
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/check_running.py';
$output = shell_exec($command);
echo $output;
}
@@ -56,7 +56,7 @@ if ($type == "RTC_time") {
}
if ($type == "sys_RTC_module_time") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/read.py';
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/RTC/read.py';
$output = shell_exec($command);
echo $output;
}
@@ -68,7 +68,7 @@ if ($type == "git_pull") {
}
if ($type == "set_RTC_withNTP") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_NTP.py';
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/RTC/set_with_NTP.py';
$output = shell_exec($command);
echo $output;
}
@@ -84,7 +84,7 @@ if ($type == "set_RTC_withBrowser") {
$rtc_time = date('Y-m-d H:i:s', strtotime($time));
// Execute Python script to update the RTC
$command = escapeshellcmd("sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py '$rtc_time'");
$command = escapeshellcmd("sudo /usr/bin/python3 /var/www/moduleair_pro_4g/RTC/set_with_browserTime.py '$rtc_time'");
$output = shell_exec($command);
if ($output === null) {
echo json_encode(['success' => false, 'message' => 'Failed to update RTC']);
@@ -95,7 +95,7 @@ if ($type == "set_RTC_withBrowser") {
if ($type == "clear_loopLogs") {
$command = 'truncate -s 0 /var/www/nebuleair_pro_4g/logs/loop.log';
$command = 'truncate -s 0 /var/www/moduleair_pro_4g/logs/loop.log';
$output = shell_exec($command);
echo $output;
}
@@ -103,7 +103,7 @@ if ($type == "clear_loopLogs") {
if ($type == "database_size") {
// Path to the SQLite database file
$databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db';
$databasePath = '/var/www/moduleair_pro_4g/sqlite/sensors.db';
// Check if the file exists
if (file_exists($databasePath)) {
@@ -172,7 +172,7 @@ if ($type == "reboot") {
if ($type == "npm") {
$port=$_GET['port'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data.py ' . $port;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/NPM/get_data.py ' . $port;
$output = shell_exec($command);
echo $output;
}
@@ -180,19 +180,19 @@ if ($type == "npm") {
if ($type == "envea") {
$port=$_GET['port'];
$name=$_GET['name'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value.py ' . $port;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/envea/read_value.py ' . $port;
$output = shell_exec($command);
echo $output;
}
if ($type == "noise") {
$command = '/var/www/nebuleair_pro_4g/sound_meter/sound_meter';
$command = '/var/www/moduleair_pro_4g/sound_meter/sound_meter';
$output = shell_exec($command);
echo $output;
}
if ($type == "BME280") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/BME280/read.py';
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/BME280/read.py';
$output = shell_exec($command);
echo $output;
}
@@ -204,13 +204,13 @@ if ($type == "table_mesure") {
$download=$_GET['download'];
if ($download==="false") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/read.py '.$table.' '.$limit;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/read.py '.$table.' '.$limit;
$output = shell_exec($command);
echo $output;
} else{
$start_date=$_GET['start_date'];
$end_date=$_GET['end_date'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/read_select_date.py '.$table.' '.$start_date.' '.$end_date;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/read_select_date.py '.$table.' '.$start_date.' '.$end_date;
$output = shell_exec($command);
echo $output;
}
@@ -223,7 +223,7 @@ if ($type == "sara") {
$sara_command=$_GET['command'];
$sara_command = escapeshellcmd($sara_command);
$timeout=$_GET['timeout'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara.py ' . $port . ' ' . $sara_command . ' ' . $timeout;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara.py ' . $port . ' ' . $sara_command . ' ' . $timeout;
$output = shell_exec($command);
echo $output;
}
@@ -232,7 +232,7 @@ if ($type == "sara") {
if ($type == "sara_getMQTT_config") {
$port=$_GET['port'];
$timeout=$_GET['timeout'];
$command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/get_config.py ' . $port . ' ' . $timeout;
$command = '/usr/bin/python3 /var/www/moduleair_pro_4g/SARA/MQTT/get_config.py ' . $port . ' ' . $timeout;
$output = shell_exec($command);
echo $output;
}
@@ -242,7 +242,7 @@ if ($type == "sara_getMQTT_login_logout") {
$port=$_GET['port'];
$timeout=$_GET['timeout'];
$login_logout=$_GET['login_logout'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/login_logout.py ' . $port . ' ' . $login_logout . ' ' . $timeout;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/MQTT/login_logout.py ' . $port . ' ' . $login_logout . ' ' . $timeout;
$output = shell_exec($command);
echo $output;
}
@@ -252,7 +252,7 @@ if ($type == "sara_MQTT_publish") {
$port=$_GET['port'];
$timeout=$_GET['timeout'];
$message=$_GET['message'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/publish.py ' . $port . ' ' . $message . ' ' . $timeout;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/MQTT/publish.py ' . $port . ' ' . $message . ' ' . $timeout;
$output = shell_exec($command);
echo $output;
}
@@ -262,11 +262,11 @@ if ($type == "sara_connectNetwork") {
$port=$_GET['port'];
$timeout=$_GET['timeout'];
$networkID=$_GET['networkID'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout;
$output = shell_exec($command);
echo $output;
#save to config.json
$configFile = '/var/www/nebuleair_pro_4g/config.json';
$configFile = '/var/www/moduleair_pro_4g/config.json';
// Read the JSON file
$jsonData = file_get_contents($configFile);
// Decode JSON data into an associative array
@@ -298,7 +298,7 @@ if ($type == "sara_setURL") {
$port=$_GET['port'];
$url=$_GET['url'];
$profile_id = 2;
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ' . $port . ' ' . $url . ' ' . $profile_id;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_setURL.py ' . $port . ' ' . $url . ' ' . $profile_id;
$output = shell_exec($command);
echo $output;
}
@@ -308,7 +308,7 @@ if ($type == "sara_APN") {
$port=$_GET['port'];
$timeout=$_GET['timeout'];
$APN_address=$_GET['APN_address'];
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setAPN.py ' . $port . ' ' . $APN_address . ' ' . $timeout;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_setAPN.py ' . $port . ' ' . $APN_address . ' ' . $timeout;
$output = shell_exec($command);
echo $output;
}
@@ -321,15 +321,15 @@ if ($type == "sara_writeMessage") {
$type2=$_GET['type2'];
if ($type2 === "write") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_writeMessage.py ' . $port . ' ' . $message;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_writeMessage.py ' . $port . ' ' . $message;
$output = shell_exec($command);
}
if ($type2 === "read") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_readMessage.py ' . $port . ' ' . $message;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_readMessage.py ' . $port . ' ' . $message;
$output = shell_exec($command);
}
if ($type2 === "erase") {
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_eraseMessage.py ' . $port . ' ' . $message;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_eraseMessage.py ' . $port . ' ' . $message;
$output = shell_exec($command);
}
@@ -342,7 +342,7 @@ if ($type == "sara_sendMessage") {
$endpoint=$_GET['endpoint'];
$endpoint = escapeshellcmd($endpoint);
$profile_id = 2;
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_sendMessage.py ' . $port . ' ' . $endpoint. ' ' . $profile_id;
$command = 'sudo /usr/bin/python3 /var/www/moduleair_pro_4g/SARA/sara_sendMessage.py ' . $port . ' ' . $endpoint. ' ' . $profile_id;
$output = shell_exec($command);
echo $output;
}
@@ -394,8 +394,8 @@ if ($type == "wifi_connect") {
echo "You will be disconnected. If connection is successfull you can find the device on your local network.";
$script_path = '/var/www/nebuleair_pro_4g/connexion.sh';
$log_file = '/var/www/nebuleair_pro_4g/logs/app.log';
$script_path = '/var/www/moduleair_pro_4g/connexion.sh';
$log_file = '/var/www/moduleair_pro_4g/logs/app.log';
shell_exec("$script_path $SSID $PASS >> $log_file 2>&1 &");
#$output = shell_exec('sudo nmcli connection down Hotspot');
@@ -407,7 +407,7 @@ if ($type == "wifi_connect") {
if ($type == "wifi_scan") {
// Set the path to your CSV file
$csvFile = '/var/www/nebuleair_pro_4g/wifi_list.csv';
$csvFile = '/var/www/moduleair_pro_4g/wifi_list.csv';
// Initialize an array to hold the JSON data
$jsonData = [];

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {

View File

@@ -51,7 +51,7 @@
<!-- New content at the bottom -->
<div class="sidebar-footer text-center text-white">
<hr>
<span class="sideBar_sensorName"> NebuleAir</span>
<span class="sideBar_sensorName"> ModuleAir</span>
</div>

View File

@@ -2,7 +2,7 @@
<nav class="navbar navbar-dark fixed-top" style="background-color: #8d8d8f;" id="topbar">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="assets/img/LogoNebuleAir.png" alt="Logo" height="30" class="d-inline-block align-text-top">
<img src="assets/img/logoModuleAirColor_long.png" alt="Logo" height="30" class="d-inline-block align-text-top">
</a>
<div class="d-flex">
<button class="btn btn-outline-light d-md-none me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarOffcanvas" aria-controls="sidebarOffcanvas" aria-label="Toggle Sidebar"></button>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<title>ModuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {

View File

@@ -15,15 +15,15 @@ Main loop to gather data from sensor inside SQLite database:
and send it to AirCarto servers via SARA R4 HTTP post requests
also send the timestamp (already stored inside the DB) !
/usr/bin/python3 /var/www/nebuleair_pro_4g/loop/SARA_send_data_v2.py
/usr/bin/python3 /var/www/moduleair_pro_4g/loop/SARA_send_data_v2.py
ATTENTION:
# This script is triggered every minutes by /var/www/nebuleair_pro_4g/master.py (as a service)
# This script is triggered every minutes by /var/www/moduleair_pro_4g/master.py (as a service)
CSV PAYLOAD (AirCarto Servers)
Endpoint:
data.nebuleair.fr
data.moduleair.fr
/pro_4G/data.php?sensor_id={device_id}&timestamp={rtc_module_time}
ATTENTION : do not change order !
@@ -51,13 +51,13 @@ CSV PAYLOAD (AirCarto Servers)
19 -> NPM hum inside
JSON PAYLOAD (Micro-Spot Servers)
Same as NebuleAir wifi
Same as moduleair wifi
Endpoint:
api-prod.uspot.probesys.net
nebuleair?token=2AFF6dQk68daFZ
moduleair?token=2AFF6dQk68daFZ
port 443
{"nebuleairid": "82D25549434",
{"moduleairid": "82D25549434",
"software_version": "ModuleAirV2-V1-042022",
"sensordatavalues":
[
@@ -113,11 +113,11 @@ if uptime_seconds < 120:
print(f"System just booted ({uptime_seconds:.2f} seconds uptime), skipping execution.")
sys.exit()
#Payload CSV to be sent to data.nebuleair.fr
#Payload CSV to be sent to data.moduleair.fr
payload_csv = [None] * 25
#Payload JSON to be sent to uSpot
payload_json = {
"nebuleairid": "XXX",
"moduleairid": "XXX",
"software_version": "ModuleAirV2-V1-042022",
"sensordatavalues": [] # Empty list to start with
}
@@ -127,7 +127,7 @@ aircarto_profile_id = 0
uSpot_profile_id = 1
# database connection
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
def blink_led(pin, blink_count, delay=1):
@@ -196,7 +196,7 @@ def update_json_key(file_path, key, value):
print(f"Error updating the JSON file: {e}")
# Define the config file path
config_file = '/var/www/nebuleair_pro_4g/config.json'
config_file = '/var/www/moduleair_pro_4g/config.json'
# Load the configuration data
config = load_config(config_file)
@@ -204,7 +204,7 @@ 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)
send_aircarto = config.get('send_aircarto', True) #envoi sur AirCarto (data.nebuleair.fr)
send_aircarto = config.get('send_aircarto', True) #envoi sur AirCarto (data.moduleair.fr)
send_uSpot = config.get('send_uSpot', False) #envoi sur MicroSpot ()
selected_networkID = config.get('SARA_R4_neworkID', '')
npm_5channel = config.get('NextPM_5channels', False) #5 canaux du NPM
@@ -212,7 +212,7 @@ npm_5channel = config.get('NextPM_5channels', False) #5 canaux du NPM
modem_config_mode = config.get('modem_config_mode', False) #modem 4G en mode configuration
#update device id in the payload json
payload_json["nebuleairid"] = device_id
payload_json["moduleairid"] = device_id
# Skip execution if modem_config_mode is true
if modem_config_mode:
@@ -555,7 +555,7 @@ try:
#Pas forcément un moyen de résoudre le soucis
#print("resetting the URL (domain name):")
#command = f'AT+UHTTP={aircarto_profile_id},1,"{url_nebuleair}"\r'
#command = f'AT+UHTTP={aircarto_profile_id},1,"{url_moduleair}"\r'
#ser_sara.write(command.encode('utf-8'))
#response_SARA_31 = read_complete_response(ser_sara)
#print(response_SARA_31)
@@ -610,7 +610,7 @@ try:
# Handle "Operation not allowed" error
if error_message == "Operation not allowed":
print('<span style="color: orange;font-weight: bold;">❓Try Resetting the HTTP Profile❓</span>')
command = f'AT+UHTTP={aircarto_profile_id},1,"data.nebuleair.fr"\r'
command = f'AT+UHTTP={aircarto_profile_id},1,"data.moduleair.fr"\r'
ser_sara.write(command.encode('utf-8'))
responseResetHTTP_profile = read_complete_response(ser_sara, timeout=5, end_of_response_timeout=5, wait_for_lines=["OK", "+CME ERROR"], debug=True)
print('<p class="text-danger-emphasis">')

85
sqlite/create_db.py Normal file
View File

@@ -0,0 +1,85 @@
'''
____ ___ _ _ _
/ ___| / _ \| | (_) |_ ___
\___ \| | | | | | | __/ _ \
___) | |_| | |___| | || __/
|____/ \__\_\_____|_|\__\___|
Script to create a sqlite database
/usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/create_db.py
in case of readonly error:
sudo chmod 777 /var/www/moduleair_pro_4g/sqlite/sensors.db
'''
import sqlite3
# Connect to (or create if not existent) the database
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
# Create a table timer
cursor.execute("""
CREATE TABLE IF NOT EXISTS timestamp_table (
id INTEGER PRIMARY KEY CHECK (id = 1), -- Enforce single row by using fixed ID
last_updated DATETIME NOT NULL
)
""")
cursor.execute("""
INSERT INTO timestamp_table (id, last_updated) VALUES (1, CURRENT_TIMESTAMP);
""")
# Create a table NPM
cursor.execute("""
CREATE TABLE IF NOT EXISTS data_NPM (
timestamp TEXT,
PM1 REAL,
PM25 REAL,
PM10 REAL,
temp_npm REAL,
hum_npm REAL
)
""")
# Create a table BME280
cursor.execute("""
CREATE TABLE IF NOT EXISTS data_BME280 (
timestamp TEXT,
temperature REAL,
humidity REAL,
pressure REAL
)
""")
# Create a table cairsens
cursor.execute("""
CREATE TABLE IF NOT EXISTS data_envea (
timestamp TEXT,
no2 REAL,
h2s REAL,
nh3 REAL,
co REAL,
o3 REAL
)
""")
# Create a table NPM_5ch
cursor.execute("""
CREATE TABLE IF NOT EXISTS data_NPM_5channels (
timestamp TEXT,
PM_ch1 INTEGER,
PM_ch2 INTEGER,
PM_ch3 INTEGER,
PM_ch4 INTEGER,
PM_ch5 INTEGER
)
""")
# Commit and close the connection
conn.commit()
conn.close()
print("Database and table created successfully!")

71
sqlite/flush_old_data.py Normal file
View File

@@ -0,0 +1,71 @@
'''
____ ___ _ _ _
/ ___| / _ \| | (_) |_ ___
\___ \| | | | | | | __/ _ \
___) | |_| | |___| | || __/
|____/ \__\_\_____|_|\__\___|
Script to flush (delete) data from a sqlite database
/usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/flush_old_data.py
Available table are
data_NPM
data_NPM_5channels
data_BME280
data_envea
timestamp_table
'''
import sqlite3
import datetime
# Connect to the SQLite database
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
#GET RTC TIME from SQlite
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
row = cursor.fetchone() # Get the first (and only) row
if row:
rtc_time_str = row[1] # Assuming timestamp is stored as TEXT (YYYY-MM-DD HH:MM:SS)
print(f"[INFO] Last recorded timestamp: {rtc_time_str}")
# Convert last_updated to a datetime object
last_updated = datetime.datetime.strptime(rtc_time_str, "%Y-%m-%d %H:%M:%S")
# Calculate the cutoff date (3 months before last_updated)
cutoff_date = last_updated - datetime.timedelta(days=60)
cutoff_date_str = cutoff_date.strftime("%Y-%m-%d %H:%M:%S")
print(f"[INFO] Deleting records older than: {cutoff_date_str}")
# List of tables to delete old data from
tables_to_clean = ["data_NPM", "data_NPM_5channels", "data_BME280", "data_envea"]
# Loop through each table and delete old data
for table in tables_to_clean:
delete_query = f"DELETE FROM {table} WHERE timestamp < ?"
cursor.execute(delete_query, (cutoff_date_str,))
print(f"[INFO] Deleted old records from {table}")
# **Commit changes before running VACUUM**
conn.commit()
print("[INFO] Changes committed successfully!")
# Now it's safe to run VACUUM
print("[INFO] Running VACUUM to optimize database space...")
cursor.execute("VACUUM")
print("[SUCCESS] Old data flushed successfully!")
else:
print("[ERROR] No timestamp found in timestamp_table.")
# Close the database connection
conn.close()

52
sqlite/read.py Normal file
View File

@@ -0,0 +1,52 @@
'''
____ ___ _ _ _
/ ___| / _ \| | (_) |_ ___
\___ \| | | | | | | __/ _ \
___) | |_| | |___| | || __/
|____/ \__\_\_____|_|\__\___|
Script to read data from a sqlite database
/usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/read.py data_NPM 10
Available table are
data_NPM
data_NPM_5channels
data_BME280
data_envea
timestamp_table
'''
import sqlite3
import sys
parameter = sys.argv[1:] # Exclude the script name
#print("Parameters received:")
table_name=parameter[0]
limit_num=parameter[1]
# Connect to the SQLite database
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
# Retrieve the last 10 sensor readings
#cursor.execute("SELECT * FROM data_NPM ORDER BY timestamp DESC LIMIT 10")
#cursor.execute("SELECT * FROM data_BME280 ORDER BY timestamp DESC LIMIT 10")
#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,))
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()

View File

@@ -0,0 +1,59 @@
'''
____ ___ _ _ _
/ ___| / _ \| | (_) |_ ___
\___ \| | | | | | | __/ _ \
___) | |_| | |___| | || __/
|____/ \__\_\_____|_|\__\___|
Script to read data from a sqlite database using start date and end date
/usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/read_select_date.py data_NPM 2025-02-09 2025-02-11
Available table are
data_NPM
data_NPM_5channels
data_BME280
data_envea
timestamp_table
'''
import sqlite3
import sys
parameter = sys.argv[1:] # Exclude the script name
#print("Parameters received:")
table_name=parameter[0]
start_date=parameter[1]
end_date=parameter[2]
# Convert to full timestamp range
start_timestamp = f"{start_date} 00:00:00"
end_timestamp = f"{end_date} 23:59:59"
# Connect to the SQLite database
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
# Retrieve the last 10 sensor readings
#cursor.execute("SELECT * FROM data_NPM ORDER BY timestamp DESC LIMIT 10")
#cursor.execute("SELECT * FROM data_BME280 ORDER BY timestamp DESC LIMIT 10")
#cursor.execute("SELECT * FROM timestamp_table")
if table_name == "timestamp_table":
cursor.execute("SELECT * FROM timestamp_table")
else:
query = f"SELECT * FROM {table_name} WHERE timestamp BETWEEN ? AND ? ORDER BY timestamp ASC"
cursor.execute(query, (start_timestamp, end_timestamp))
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()

33
sqlite/write.py Normal file
View File

@@ -0,0 +1,33 @@
'''
____ ___ _ _ _
/ ___| / _ \| | (_) |_ ___
\___ \| | | | | | | __/ _ \
___) | |_| | |___| | || __/
|____/ \__\_\_____|_|\__\___|
Script to write data to a sqlite database
/usr/bin/python3 /var/www/moduleair_pro_4g/sqlite/write.py
'''
import sqlite3
# Connect to the SQLite database
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
# Insert a sample temperature reading
timestamp = "2025-10-11"
PM1 = 25.3
PM25 = 18.3
PM10 = 9.3
cursor.execute('''
INSERT INTO data (timestamp, PM1, PM25, PM10) VALUES (?,?,?,?,?)'''
, (timestamp,PM1,PM25,PM10))
# Commit and close the connection
conn.commit()
conn.close()
print("Sensor data saved successfully!")