update
This commit is contained in:
@@ -24,20 +24,7 @@ import sqlite3
|
|||||||
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
|
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
def load_config(config_file):
|
mh_z19_port = "/dev/ttyAMA4" #port du NPM solo
|
||||||
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 {}
|
|
||||||
|
|
||||||
|
|
||||||
# Load the configuration data
|
|
||||||
config_file = '/var/www/moduleair_pro_4g/config.json'
|
|
||||||
config = load_config(config_file)
|
|
||||||
mh_z19_port = config.get('MH-Z19_port', '') #port du NPM solo
|
|
||||||
|
|
||||||
ser = serial.Serial(
|
ser = serial.Serial(
|
||||||
port=mh_z19_port,
|
port=mh_z19_port,
|
||||||
|
|||||||
@@ -42,19 +42,8 @@ import time
|
|||||||
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
|
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
def load_config(config_file):
|
npm_solo_port = "/dev/ttyAMA3" #port du NPM solo
|
||||||
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 {}
|
|
||||||
|
|
||||||
# Load the configuration data
|
|
||||||
config_file = '/var/www/moduleair_pro_4g/config.json'
|
|
||||||
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")
|
||||||
|
|||||||
417
html/admin.html
417
html/admin.html
@@ -59,48 +59,9 @@
|
|||||||
|
|
||||||
<form>
|
<form>
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
<div class="form-check form-switch mb-2">
|
|
||||||
<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 class="form-check form-switch mb-2">
|
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="flex_loop_log" onchange="update_config('loop_log', this.checked)">
|
|
||||||
<label class="form-check-label" for="flex_loop_log">Loop Logs</label>
|
|
||||||
</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">
|
|
||||||
<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">
|
|
||||||
Next PM 5 canaux
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-check mb-3">
|
|
||||||
<input class="form-check-input" type="checkbox" value="" id="check_bme280" onchange="update_config('BME280/get_data_v2.py', this.checked)">
|
|
||||||
<label class="form-check-label" for="check_bme280">
|
|
||||||
Sonde temp/hum (BME280)
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-check mb-3">
|
|
||||||
<input class="form-check-input" type="checkbox" value="" id="check_envea" onchange="update_config('envea/read_value_v2.py', this.checked)">
|
|
||||||
<label class="form-check-label" for="check_envea">
|
|
||||||
Sonde Envea
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="device_name" class="form-label">Device Name</label>
|
<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)">
|
<input type="text" class="form-control" id="device_name" onchange="update_config_sqlite('deviceName', this.value)">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -108,6 +69,49 @@
|
|||||||
<input type="text" class="form-control" id="device_ID" disabled>
|
<input type="text" class="form-control" id="device_ID" disabled>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- config_scripts_table -->
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_NPM" onchange="update_config_scripts_sqlite('NPM/get_data_modbus_v3.py', this.checked)">
|
||||||
|
<label class="form-check-label" for="check_NPM">
|
||||||
|
Next PM
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_NPM_5channels" onchange="update_config_sqlite('npm_5channel', this.checked)">
|
||||||
|
<label class="form-check-label" for="check_NPM_5channels">
|
||||||
|
Next PM send 5 channels (no script)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_bme280" onchange="update_config_scripts_sqlite('BME280/get_data_v2.py', this.checked)">
|
||||||
|
<label class="form-check-label" for="check_bme280">
|
||||||
|
Sonde temp/hum (BME280)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_CO2" onchange="update_config_scripts_sqlite('MH-Z19/write_data.py', this.checked)">
|
||||||
|
<label class="form-check-label" for="check_CO2">
|
||||||
|
Sonde CO2 (MH-Z19)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="" id="check_sensirionSFA30" onchange="update_config_scripts_sqlite('sensirion/SFA30_read.py', this.checked)">
|
||||||
|
<label class="form-check-label" for="check_sensirionSFA30">
|
||||||
|
Sonde Formaldehyde (Sensiririon SFA30)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3" id="sondes_envea_div"></div>
|
||||||
|
|
||||||
|
<div id="envea_table"></div>
|
||||||
|
|
||||||
|
|
||||||
<!--<button type="submit" class="btn btn-primary">Submit</button>-->
|
<!--<button type="submit" class="btn btn-primary">Submit</button>-->
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,12 +121,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>
|
||||||
@@ -155,12 +153,25 @@
|
|||||||
|
|
||||||
<div class="col-lg-4 col-12">
|
<div class="col-lg-4 col-12">
|
||||||
<h3 class="mt-4">Updates</h3>
|
<h3 class="mt-4">Updates</h3>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary" onclick="updateGitPull()">Update firmware</button>
|
<button type="submit" class="btn btn-primary" onclick="updateGitPull()">Update firmware</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- toast -->
|
||||||
|
|
||||||
|
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||||
|
<div id="liveToast" class="toast align-items-center text-bg-primary border-1" role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="toast-body">
|
||||||
|
Hello, world! This is a toast message.
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -193,112 +204,248 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//end document.addEventListener
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
___ _ _
|
||||||
|
/ _ \ _ __ | | ___ __ _ __| |
|
||||||
|
| | | | '_ \| | / _ \ / _` |/ _` |
|
||||||
|
| |_| | | | | |__| (_) | (_| | (_| |
|
||||||
|
\___/|_| |_|_____\___/ \__,_|\__,_|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
|
||||||
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
|
//NEW way to get config (SQLite)
|
||||||
.then(response => response.json()) // Parse response as JSON
|
$.ajax({
|
||||||
.then(data => {
|
url: 'launcher.php?type=get_config_sqlite',
|
||||||
console.log("Getting config file (onload)");
|
dataType:'json',
|
||||||
//get device ID
|
//dataType: 'json', // Specify that you expect a JSON response
|
||||||
const deviceID = data.deviceID.trim().toUpperCase();
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
//document.getElementById('pageTitle_plus_ID').innerText = 'token: ' + deviceID;
|
success: function(response) {
|
||||||
//get device Name
|
console.log("Getting SQLite config table:");
|
||||||
const deviceName = data.deviceName;
|
console.log(response);
|
||||||
|
//device name
|
||||||
console.log("Device Name: " + deviceName);
|
const deviceName = document.getElementById("device_name");
|
||||||
console.log("Device ID: " + deviceID);
|
deviceName.value = response.deviceName;
|
||||||
|
//device name_side bar
|
||||||
|
const elements = document.querySelectorAll('.sideBar_sensorName');
|
||||||
|
elements.forEach((element) => {
|
||||||
|
element.innerText = response.deviceName;
|
||||||
|
});
|
||||||
|
//device ID
|
||||||
|
const deviceID = response.deviceID.trim().toUpperCase();
|
||||||
|
const device_ID = document.getElementById("device_ID");
|
||||||
|
device_ID.value = response.deviceID.toUpperCase();
|
||||||
|
//nextPM send 5 channels
|
||||||
|
const checkbox_nmp5channels = document.getElementById("check_NPM_5channels");
|
||||||
|
checkbox_nmp5channels.checked = response.npm_5channel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const elements = document.querySelectorAll('.sideBar_sensorName');
|
|
||||||
elements.forEach((element) => {
|
|
||||||
element.innerText = deviceName;
|
|
||||||
});
|
|
||||||
|
|
||||||
//get BME check
|
},
|
||||||
const checkbox = document.getElementById("check_bme280");
|
error: function(xhr, status, error) {
|
||||||
checkbox.checked = data["BME280/get_data_v2.py"];
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});//end AJAX
|
||||||
|
|
||||||
//get NPM-5channels check
|
//getting config_scripts table
|
||||||
const checkbox_NPM_5channels = document.getElementById("check_NPM_5channels");
|
$.ajax({
|
||||||
checkbox_NPM_5channels.checked = data["NextPM_5channels"];
|
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);
|
||||||
|
|
||||||
//get sonde Envea check
|
const checkbox_NPM = document.getElementById("check_NPM");
|
||||||
const checkbox_envea = document.getElementById("check_envea");
|
const checkbox_bme = document.getElementById("check_bme280");
|
||||||
checkbox_envea.checked = data["envea/read_value_v2.py"];
|
const checkbox_CO2 = document.getElementById("check_CO2");
|
||||||
|
const checkbox_SFA30 = document.getElementById("check_sensirionSFA30");
|
||||||
|
|
||||||
//get RTC check
|
checkbox_NPM.checked = response["NPM/get_data_modbus_v3.py"];
|
||||||
const checkbox_RTC = document.getElementById("check_RTC");
|
checkbox_bme.checked = response["BME280/get_data_v2.py"];
|
||||||
checkbox_RTC.checked = data.i2c_RTC;
|
checkbox_SFA30.checked = response["sensirion/SFA30_read.py"];
|
||||||
|
checkbox_CO2.checked = response["MH-Z19/write_data.py"];
|
||||||
|
|
||||||
|
//si sonde envea is true
|
||||||
|
if (response["envea/read_value_v2.py"]) {
|
||||||
|
add_sondeEnveaContainer();
|
||||||
|
|
||||||
//device name
|
}
|
||||||
const device_name = document.getElementById("device_name");
|
},
|
||||||
device_name.value = data.deviceName;
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});//end AJAX
|
||||||
|
|
||||||
//device ID
|
//get system time and RTC module
|
||||||
const device_ID = document.getElementById("device_ID");
|
$.ajax({
|
||||||
device_ID.value = data.deviceID.toUpperCase();
|
url: 'launcher.php?type=sys_RTC_module_time',
|
||||||
|
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);
|
||||||
|
// Update the input fields with the received JSON data
|
||||||
|
document.getElementById("sys_local_time").value = response.system_local_time;
|
||||||
|
document.getElementById("sys_UTC_time").value = response.system_utc_time;
|
||||||
|
document.getElementById("RTC_utc_time").value = response.rtc_module_time;
|
||||||
|
|
||||||
//get system time and RTC module
|
// Get the time difference
|
||||||
$.ajax({
|
const timeDiff = response.time_difference_seconds;
|
||||||
url: 'launcher.php?type=sys_RTC_module_time',
|
|
||||||
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);
|
|
||||||
// Update the input fields with the received JSON data
|
|
||||||
document.getElementById("sys_local_time").value = response.system_local_time;
|
|
||||||
document.getElementById("sys_UTC_time").value = response.system_utc_time;
|
|
||||||
document.getElementById("RTC_utc_time").value = response.rtc_module_time;
|
|
||||||
|
|
||||||
// Get the time difference
|
// Reference to the alert container
|
||||||
const timeDiff = response.time_difference_seconds;
|
const alertContainer = document.getElementById("alert_container");
|
||||||
|
|
||||||
// Reference to the alert container
|
// Remove any previous alert
|
||||||
const alertContainer = document.getElementById("alert_container");
|
alertContainer.innerHTML = "";
|
||||||
|
|
||||||
// Remove any previous alert
|
// Add an alert based on time difference
|
||||||
alertContainer.innerHTML = "";
|
if (typeof timeDiff === "number") {
|
||||||
|
if (timeDiff >= 0 && timeDiff <= 10) {
|
||||||
// Add an alert based on time difference
|
alertContainer.innerHTML = `
|
||||||
if (typeof timeDiff === "number") {
|
<div class="alert alert-success" role="alert">
|
||||||
if (timeDiff >= 0 && timeDiff <= 10) {
|
RTC and system time are in sync (Difference: ${timeDiff} sec).
|
||||||
alertContainer.innerHTML = `
|
</div>`;
|
||||||
<div class="alert alert-success" role="alert">
|
} else if (timeDiff > 10) {
|
||||||
RTC and system time are in sync (Difference: ${timeDiff} sec).
|
alertContainer.innerHTML = `
|
||||||
</div>`;
|
<div class="alert alert-danger" role="alert">
|
||||||
} else if (timeDiff > 10) {
|
RTC time is out of sync! (Difference: ${timeDiff} sec).
|
||||||
alertContainer.innerHTML = `
|
</div>`;
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
RTC time is out of sync! (Difference: ${timeDiff} sec).
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error('AJAX request failed:', status, error);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});//end ajax
|
||||||
|
|
||||||
//get local RTC
|
//get local RTC
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'launcher.php?type=RTC_time',
|
url: 'launcher.php?type=RTC_time',
|
||||||
dataType: 'text', // Specify that you expect a JSON response
|
dataType: 'text', // Specify that you expect a JSON response
|
||||||
method: 'GET', // Use GET or POST depending on your needs
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
console.log("Local RTC: " + response);
|
console.log("Local RTC: " + response);
|
||||||
const RTC_Element = document.getElementById("RTC_time");
|
const RTC_Element = document.getElementById("RTC_time");
|
||||||
RTC_Element.textContent = response;
|
RTC_Element.textContent = response;
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
console.error('AJAX request failed:', status, error);
|
console.error('AJAX request failed:', status, error);
|
||||||
}
|
}
|
||||||
});
|
});//end ajax
|
||||||
|
|
||||||
})
|
} //end windows on load
|
||||||
.catch(error => console.error('Error loading config.json:', error));
|
|
||||||
}
|
function update_config_sqlite(param, value){
|
||||||
|
console.log("Updating sqlite ",param," : ", value);
|
||||||
|
const toastLiveExample = document.getElementById('liveToast')
|
||||||
|
const toastBody = toastLiveExample.querySelector('.toast-body');
|
||||||
|
$.ajax({
|
||||||
|
url: 'launcher.php?type=update_config_sqlite¶m='+param+'&value='+value,
|
||||||
|
dataType: 'json', // 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);
|
||||||
|
// Format the response nicely
|
||||||
|
let formattedMessage = '';
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
// Success message
|
||||||
|
toastLiveExample.classList.remove('text-bg-danger');
|
||||||
|
toastLiveExample.classList.add('text-bg-success');
|
||||||
|
|
||||||
|
formattedMessage = `
|
||||||
|
<strong>Success!</strong><br>
|
||||||
|
Parameter: ${response.param || param}<br>
|
||||||
|
Value: ${response.value || checked}<br>
|
||||||
|
${response.message || ''}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
// Error message
|
||||||
|
toastLiveExample.classList.remove('text-bg-success');
|
||||||
|
toastLiveExample.classList.add('text-bg-danger');
|
||||||
|
|
||||||
|
formattedMessage = `
|
||||||
|
<strong>Error!</strong><br>
|
||||||
|
${response.error || 'Unknown error'}<br>
|
||||||
|
Parameter: ${response.param || param}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the toast body with formatted content
|
||||||
|
toastBody.innerHTML = formattedMessage;
|
||||||
|
// Show the toast
|
||||||
|
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
|
||||||
|
toastBootstrap.show()
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_config_scripts_sqlite(param, value) {
|
||||||
|
console.log("Updating scripts sqlite ", param, " : ", value);
|
||||||
|
const toastLiveExample = document.getElementById('liveToast')
|
||||||
|
const toastBody = toastLiveExample.querySelector('.toast-body');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'launcher.php?type=update_config_scripts_sqlite¶m=' + param + '&value=' + value,
|
||||||
|
dataType: 'json',
|
||||||
|
method: 'GET',
|
||||||
|
cache: false,
|
||||||
|
success: function(response) {
|
||||||
|
console.log(response);
|
||||||
|
// Format the response nicely
|
||||||
|
let formattedMessage = '';
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
// Success message
|
||||||
|
toastLiveExample.classList.remove('text-bg-danger');
|
||||||
|
toastLiveExample.classList.add('text-bg-success');
|
||||||
|
|
||||||
|
formattedMessage = `
|
||||||
|
<strong>Success!</strong><br>
|
||||||
|
Parameter: ${response.script_path || param}<br>
|
||||||
|
Value: ${response.enabled !== undefined ? response.enabled : value}<br>
|
||||||
|
${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');
|
||||||
|
toastLiveExample.classList.add('text-bg-danger');
|
||||||
|
|
||||||
|
formattedMessage = `
|
||||||
|
<strong>Error!</strong><br>
|
||||||
|
${response.error || 'Unknown error'}<br>
|
||||||
|
Parameter: ${response.script_path || param}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the toast body with formatted content
|
||||||
|
toastBody.innerHTML = formattedMessage;
|
||||||
|
// Show the toast
|
||||||
|
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
|
||||||
|
toastBootstrap.show()
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function update_config(param, value){
|
function update_config(param, value){
|
||||||
|
|||||||
@@ -151,42 +151,48 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
|
|
||||||
.then(response => response.json()) // Parse response as JSON
|
|
||||||
.then(data => {
|
|
||||||
console.log("Getting config file (onload)");
|
|
||||||
//get device ID
|
|
||||||
const deviceID = data.deviceID.trim().toUpperCase();
|
|
||||||
//document.getElementById('pageTitle_plus_ID').innerText = 'token: ' + deviceID;
|
|
||||||
|
|
||||||
//get device Name
|
//NEW way to get config (SQLite)
|
||||||
const deviceName = data.deviceName;
|
$.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);
|
||||||
|
|
||||||
const elements = document.querySelectorAll('.sideBar_sensorName');
|
//device name_side bar
|
||||||
elements.forEach((element) => {
|
const elements = document.querySelectorAll('.sideBar_sensorName');
|
||||||
element.innerText = deviceName;
|
elements.forEach((element) => {
|
||||||
});
|
element.innerText = response.deviceName;
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});//end AJAX
|
||||||
|
|
||||||
|
|
||||||
//get local RTC
|
//get local RTC
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'launcher.php?type=RTC_time',
|
url: 'launcher.php?type=RTC_time',
|
||||||
dataType: 'text', // Specify that you expect a JSON response
|
dataType: 'text', // Specify that you expect a JSON response
|
||||||
method: 'GET', // Use GET or POST depending on your needs
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
console.log("Local RTC: " + response);
|
console.log("Local RTC: " + response);
|
||||||
const RTC_Element = document.getElementById("RTC_time");
|
const RTC_Element = document.getElementById("RTC_time");
|
||||||
RTC_Element.textContent = response;
|
RTC_Element.textContent = response;
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
console.error('AJAX request failed:', status, error);
|
console.error('AJAX request failed:', status, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
|
||||||
.catch(error => console.error('Error loading config.json:', error));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
558
html/index.html
558
html/index.html
@@ -135,296 +135,296 @@
|
|||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
|
||||||
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
|
//NEW way to get config (SQLite)
|
||||||
.then(response => response.json()) // Parse response as JSON
|
$.ajax({
|
||||||
.then(data => {
|
url: 'launcher.php?type=get_config_sqlite',
|
||||||
console.log("Getting config file (onload)");
|
dataType:'json',
|
||||||
//get device ID
|
//dataType: 'json', // Specify that you expect a JSON response
|
||||||
const deviceID = data.deviceID.trim().toUpperCase();
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
//document.getElementById('pageTitle_plus_ID').innerText = 'token: ' + deviceID;
|
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
|
||||||
|
|
||||||
|
|
||||||
//get device Name
|
//get local RTC
|
||||||
const deviceName = data.deviceName;
|
$.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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const elements = document.querySelectorAll('.sideBar_sensorName');
|
//get database size
|
||||||
elements.forEach((element) => {
|
$.ajax({
|
||||||
element.innerText = deviceName;
|
url: 'launcher.php?type=database_size',
|
||||||
});
|
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);
|
||||||
|
|
||||||
//get local RTC
|
if (response.size_megabytes !== undefined) {
|
||||||
$.ajax({
|
// Extract and format the size in MB
|
||||||
url: 'launcher.php?type=RTC_time',
|
const databaseSizeMB = response.size_megabytes + " MB";
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//get database size
|
// Update the HTML element with the database size
|
||||||
$.ajax({
|
const databaseSizeElement = document.getElementById("database_size");
|
||||||
url: 'launcher.php?type=database_size',
|
databaseSizeElement.textContent = databaseSizeMB;
|
||||||
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);
|
|
||||||
|
|
||||||
if (response.size_megabytes !== undefined) {
|
console.log("Database size:", databaseSizeMB);
|
||||||
// Extract and format the size in MB
|
} else if (response.error) {
|
||||||
const databaseSizeMB = response.size_megabytes + " MB";
|
// Handle errors from the PHP response
|
||||||
|
console.error("Error from server:", response.error);
|
||||||
// Update the HTML element with the database size
|
}
|
||||||
const databaseSizeElement = document.getElementById("database_size");
|
},
|
||||||
databaseSizeElement.textContent = databaseSizeMB;
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
console.log("Database size:", databaseSizeMB);
|
|
||||||
} else if (response.error) {
|
|
||||||
// Handle errors from the PHP response
|
|
||||||
console.error("Error from server:", response.error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error('AJAX request failed:', status, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//get disk free space
|
|
||||||
$.ajax({
|
|
||||||
url: 'launcher.php?type=linux_disk',
|
|
||||||
dataType: 'text', // Specify that you expect a JSON response
|
|
||||||
method: 'GET', // Use GET or POST depending on your needs
|
|
||||||
success: function(response) {
|
|
||||||
console.log("Linux disk space: " + response);
|
|
||||||
//1. disk size
|
|
||||||
const disk_size = document.getElementById("disk_size");
|
|
||||||
const firstNumber = response.match(/(?<!\w)(\d+(\.\d+)?)(?=\D)/)[1];
|
|
||||||
|
|
||||||
disk_size.innerHTML = firstNumber;
|
|
||||||
//2. Free space
|
|
||||||
const match = response.match(/(\d+)%/);
|
|
||||||
const diskSpace = document.getElementById("disk_space");
|
|
||||||
const percentage = match[1];
|
|
||||||
|
|
||||||
// Create the outer div with class and attributes
|
|
||||||
const progressDiv = document.createElement('div');
|
|
||||||
progressDiv.className = 'progress mb-3';
|
|
||||||
progressDiv.setAttribute('role', 'progressbar');
|
|
||||||
progressDiv.setAttribute('aria-label', 'Example with label');
|
|
||||||
progressDiv.setAttribute('aria-valuenow', percentage);
|
|
||||||
progressDiv.setAttribute('aria-valuemin', 0);
|
|
||||||
progressDiv.setAttribute('aria-valuemax', 100);
|
|
||||||
|
|
||||||
// Create the inner progress bar div
|
|
||||||
const progressBarDiv = document.createElement('div');
|
|
||||||
progressBarDiv.className = 'progress-bar';
|
|
||||||
progressBarDiv.style.width = `${percentage}%`; // Set the width dynamically
|
|
||||||
progressBarDiv.textContent = `${percentage}%`; // Set the text dynamically
|
|
||||||
|
|
||||||
// Append the progress bar to the outer div
|
|
||||||
progressDiv.appendChild(progressBarDiv);
|
|
||||||
|
|
||||||
// Append the entire progress bar to the body (or any other container)
|
|
||||||
diskSpace.appendChild(progressDiv);
|
|
||||||
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error('AJAX request failed:', status, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//get memory free space
|
|
||||||
$.ajax({
|
|
||||||
url: 'launcher.php?type=linux_memory',
|
|
||||||
dataType: 'text', // Specify that you expect a JSON response
|
|
||||||
method: 'GET', // Use GET or POST depending on your needs
|
|
||||||
success: function(response) {
|
|
||||||
console.log("Linux memory space: " + response);
|
|
||||||
//1. memory size
|
|
||||||
const memory_size = document.getElementById("memory_size");
|
|
||||||
const memorySpace = document.getElementById("memory_space");
|
|
||||||
|
|
||||||
|
|
||||||
const memLine = response.match(/Mem:\s+(\d+\.?\d*)Mi\s+(\d+\.?\d*)Mi/);
|
|
||||||
const totalMemory = parseFloat(memLine[1]); // Total memory in MiB
|
|
||||||
const usedMemory = parseFloat(memLine[2]); // Used memory in MiB
|
|
||||||
|
|
||||||
// Calculate the percentage
|
|
||||||
const percentageUsed = ((usedMemory / totalMemory) * 100).toFixed(2);
|
|
||||||
|
|
||||||
console.log(totalMemory);
|
|
||||||
|
|
||||||
memory_size.innerHTML = totalMemory;
|
|
||||||
|
|
||||||
|
|
||||||
console.log(usedMemory);
|
|
||||||
console.log(percentageUsed);
|
|
||||||
|
|
||||||
// Create the outer div with class and attributes
|
|
||||||
const progressDiv = document.createElement('div');
|
|
||||||
progressDiv.className = 'progress mb-3';
|
|
||||||
progressDiv.setAttribute('role', 'progressbar');
|
|
||||||
progressDiv.setAttribute('aria-label', 'Example with label');
|
|
||||||
progressDiv.setAttribute('aria-valuenow', percentageUsed);
|
|
||||||
progressDiv.setAttribute('aria-valuemin', 0);
|
|
||||||
progressDiv.setAttribute('aria-valuemax', 100);
|
|
||||||
|
|
||||||
// Create the inner progress bar div
|
|
||||||
const progressBarDiv = document.createElement('div');
|
|
||||||
progressBarDiv.className = 'progress-bar';
|
|
||||||
progressBarDiv.style.width = `${percentageUsed}%`; // Set the width dynamically
|
|
||||||
progressBarDiv.textContent = `${percentageUsed}%`; // Set the text dynamically
|
|
||||||
|
|
||||||
// Append the progress bar to the outer div
|
|
||||||
progressDiv.appendChild(progressBarDiv);
|
|
||||||
|
|
||||||
// Append the entire progress bar to the body (or any other container)
|
|
||||||
memorySpace.appendChild(progressDiv);
|
|
||||||
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error('AJAX request failed:', status, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// GET NPM SQLite values
|
|
||||||
$.ajax({
|
|
||||||
url: 'launcher.php?type=get_npm_sqlite_data',
|
|
||||||
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);
|
|
||||||
updatePMChart(response);
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error('AJAX request failed:', status, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let chart; // Store the Chart.js instance globally
|
|
||||||
|
|
||||||
function updatePMChart(data) {
|
|
||||||
const labels = data.map(d => d.timestamp);
|
|
||||||
const PM1 = data.map(d => d.PM1);
|
|
||||||
const PM25 = data.map(d => d.PM25);
|
|
||||||
const PM10 = data.map(d => d.PM10);
|
|
||||||
|
|
||||||
const ctx = document.getElementById('sensorPMChart').getContext('2d');
|
|
||||||
|
|
||||||
if (!chart) {
|
|
||||||
chart = new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: "PM1",
|
|
||||||
data: PM1,
|
|
||||||
borderColor: "rgba(0, 51, 153, 1)",
|
|
||||||
backgroundColor: "rgba(0, 51, 153, 0.2)", // Very light blue background
|
|
||||||
fill: true,
|
|
||||||
tension: 0.4, // Smooth curves
|
|
||||||
pointRadius: 2, // Larger points
|
|
||||||
pointHoverRadius: 6 // Bigger hover points
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "PM2.5",
|
|
||||||
data: PM25,
|
|
||||||
borderColor: "rgba(30, 144, 255, 1)",
|
|
||||||
backgroundColor: "rgba(30, 144, 255, 0.2)", // Very light medium blue background
|
|
||||||
fill: true,
|
|
||||||
tension: 0.4,
|
|
||||||
pointRadius: 2,
|
|
||||||
pointHoverRadius: 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "PM10",
|
|
||||||
data: PM10,
|
|
||||||
borderColor: "rgba(135, 206, 250, 1)",
|
|
||||||
backgroundColor: "rgba(135, 206, 250, 0.2)", // Very light blue background
|
|
||||||
fill: true,
|
|
||||||
tension: 0.4,
|
|
||||||
pointRadius: 2,
|
|
||||||
pointHoverRadius: 6
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: true,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'top'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Time (UTC)',
|
|
||||||
font: {
|
|
||||||
size: 16,
|
|
||||||
family: 'Arial, sans-serif'
|
|
||||||
},
|
|
||||||
color: '#4A4A4A'
|
|
||||||
},
|
|
||||||
ticks: {
|
|
||||||
autoSkip: true,
|
|
||||||
maxTicksLimit: 5,
|
|
||||||
color: '#4A4A4A',
|
|
||||||
callback: function(value, index) {
|
|
||||||
// Access the correct label from the `labels` array
|
|
||||||
const label = labels[index]; // Use the original `labels` array
|
|
||||||
if (label && typeof label === 'string' && label.includes(' ')) {
|
|
||||||
return label.split(' ')[1].slice(0, 5); // Extract "HH:MM"
|
|
||||||
}
|
|
||||||
return value; // Fallback for invalid labels
|
|
||||||
}
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
display: false // Remove gridlines for a cleaner look
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Values (µg/m³)',
|
|
||||||
font: {
|
|
||||||
size: 16,
|
|
||||||
family: 'Arial, sans-serif'
|
|
||||||
},
|
|
||||||
color: '#4A4A4A'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
chart.data.labels = labels;
|
|
||||||
chart.data.datasets[0].data = PM1;
|
|
||||||
chart.data.datasets[1].data = PM25;
|
|
||||||
chart.data.datasets[2].data = PM10;
|
|
||||||
chart.update();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//get disk free space
|
||||||
|
$.ajax({
|
||||||
|
url: 'launcher.php?type=linux_disk',
|
||||||
|
dataType: 'text', // Specify that you expect a JSON response
|
||||||
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
|
success: function(response) {
|
||||||
|
console.log("Linux disk space: " + response);
|
||||||
|
//1. disk size
|
||||||
|
const disk_size = document.getElementById("disk_size");
|
||||||
|
const firstNumber = response.match(/(?<!\w)(\d+(\.\d+)?)(?=\D)/)[1];
|
||||||
|
|
||||||
|
disk_size.innerHTML = firstNumber;
|
||||||
|
//2. Free space
|
||||||
|
const match = response.match(/(\d+)%/);
|
||||||
|
const diskSpace = document.getElementById("disk_space");
|
||||||
|
const percentage = match[1];
|
||||||
|
|
||||||
|
// Create the outer div with class and attributes
|
||||||
|
const progressDiv = document.createElement('div');
|
||||||
|
progressDiv.className = 'progress mb-3';
|
||||||
|
progressDiv.setAttribute('role', 'progressbar');
|
||||||
|
progressDiv.setAttribute('aria-label', 'Example with label');
|
||||||
|
progressDiv.setAttribute('aria-valuenow', percentage);
|
||||||
|
progressDiv.setAttribute('aria-valuemin', 0);
|
||||||
|
progressDiv.setAttribute('aria-valuemax', 100);
|
||||||
|
|
||||||
|
// Create the inner progress bar div
|
||||||
|
const progressBarDiv = document.createElement('div');
|
||||||
|
progressBarDiv.className = 'progress-bar';
|
||||||
|
progressBarDiv.style.width = `${percentage}%`; // Set the width dynamically
|
||||||
|
progressBarDiv.textContent = `${percentage}%`; // Set the text dynamically
|
||||||
|
|
||||||
|
// Append the progress bar to the outer div
|
||||||
|
progressDiv.appendChild(progressBarDiv);
|
||||||
|
|
||||||
|
// Append the entire progress bar to the body (or any other container)
|
||||||
|
diskSpace.appendChild(progressDiv);
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//get memory free space
|
||||||
|
$.ajax({
|
||||||
|
url: 'launcher.php?type=linux_memory',
|
||||||
|
dataType: 'text', // Specify that you expect a JSON response
|
||||||
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
|
success: function(response) {
|
||||||
|
console.log("Linux memory space: " + response);
|
||||||
|
//1. memory size
|
||||||
|
const memory_size = document.getElementById("memory_size");
|
||||||
|
const memorySpace = document.getElementById("memory_space");
|
||||||
|
|
||||||
|
|
||||||
|
const memLine = response.match(/Mem:\s+(\d+\.?\d*)Mi\s+(\d+\.?\d*)Mi/);
|
||||||
|
const totalMemory = parseFloat(memLine[1]); // Total memory in MiB
|
||||||
|
const usedMemory = parseFloat(memLine[2]); // Used memory in MiB
|
||||||
|
|
||||||
|
// Calculate the percentage
|
||||||
|
const percentageUsed = ((usedMemory / totalMemory) * 100).toFixed(2);
|
||||||
|
|
||||||
|
console.log(totalMemory);
|
||||||
|
|
||||||
|
memory_size.innerHTML = totalMemory;
|
||||||
|
|
||||||
|
|
||||||
|
console.log(usedMemory);
|
||||||
|
console.log(percentageUsed);
|
||||||
|
|
||||||
|
// Create the outer div with class and attributes
|
||||||
|
const progressDiv = document.createElement('div');
|
||||||
|
progressDiv.className = 'progress mb-3';
|
||||||
|
progressDiv.setAttribute('role', 'progressbar');
|
||||||
|
progressDiv.setAttribute('aria-label', 'Example with label');
|
||||||
|
progressDiv.setAttribute('aria-valuenow', percentageUsed);
|
||||||
|
progressDiv.setAttribute('aria-valuemin', 0);
|
||||||
|
progressDiv.setAttribute('aria-valuemax', 100);
|
||||||
|
|
||||||
|
// Create the inner progress bar div
|
||||||
|
const progressBarDiv = document.createElement('div');
|
||||||
|
progressBarDiv.className = 'progress-bar';
|
||||||
|
progressBarDiv.style.width = `${percentageUsed}%`; // Set the width dynamically
|
||||||
|
progressBarDiv.textContent = `${percentageUsed}%`; // Set the text dynamically
|
||||||
|
|
||||||
|
// Append the progress bar to the outer div
|
||||||
|
progressDiv.appendChild(progressBarDiv);
|
||||||
|
|
||||||
|
// Append the entire progress bar to the body (or any other container)
|
||||||
|
memorySpace.appendChild(progressDiv);
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// GET NPM SQLite values
|
||||||
|
$.ajax({
|
||||||
|
url: 'launcher.php?type=get_npm_sqlite_data',
|
||||||
|
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);
|
||||||
|
updatePMChart(response);
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let chart; // Store the Chart.js instance globally
|
||||||
|
|
||||||
|
function updatePMChart(data) {
|
||||||
|
const labels = data.map(d => d.timestamp);
|
||||||
|
const PM1 = data.map(d => d.PM1);
|
||||||
|
const PM25 = data.map(d => d.PM25);
|
||||||
|
const PM10 = data.map(d => d.PM10);
|
||||||
|
|
||||||
|
const ctx = document.getElementById('sensorPMChart').getContext('2d');
|
||||||
|
|
||||||
|
if (!chart) {
|
||||||
|
chart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "PM1",
|
||||||
|
data: PM1,
|
||||||
|
borderColor: "rgba(0, 51, 153, 1)",
|
||||||
|
backgroundColor: "rgba(0, 51, 153, 0.2)", // Very light blue background
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4, // Smooth curves
|
||||||
|
pointRadius: 2, // Larger points
|
||||||
|
pointHoverRadius: 6 // Bigger hover points
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "PM2.5",
|
||||||
|
data: PM25,
|
||||||
|
borderColor: "rgba(30, 144, 255, 1)",
|
||||||
|
backgroundColor: "rgba(30, 144, 255, 0.2)", // Very light medium blue background
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4,
|
||||||
|
pointRadius: 2,
|
||||||
|
pointHoverRadius: 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "PM10",
|
||||||
|
data: PM10,
|
||||||
|
borderColor: "rgba(135, 206, 250, 1)",
|
||||||
|
backgroundColor: "rgba(135, 206, 250, 0.2)", // Very light blue background
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4,
|
||||||
|
pointRadius: 2,
|
||||||
|
pointHoverRadius: 6
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Time (UTC)',
|
||||||
|
font: {
|
||||||
|
size: 16,
|
||||||
|
family: 'Arial, sans-serif'
|
||||||
|
},
|
||||||
|
color: '#4A4A4A'
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
autoSkip: true,
|
||||||
|
maxTicksLimit: 5,
|
||||||
|
color: '#4A4A4A',
|
||||||
|
callback: function(value, index) {
|
||||||
|
// Access the correct label from the `labels` array
|
||||||
|
const label = labels[index]; // Use the original `labels` array
|
||||||
|
if (label && typeof label === 'string' && label.includes(' ')) {
|
||||||
|
return label.split(' ')[1].slice(0, 5); // Extract "HH:MM"
|
||||||
|
}
|
||||||
|
return value; // Fallback for invalid labels
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
display: false // Remove gridlines for a cleaner look
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: 'Values (µg/m³)',
|
||||||
|
font: {
|
||||||
|
size: 16,
|
||||||
|
family: 'Arial, sans-serif'
|
||||||
|
},
|
||||||
|
color: '#4A4A4A'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
chart.data.labels = labels;
|
||||||
|
chart.data.datasets[0].data = PM1;
|
||||||
|
chart.data.datasets[1].data = PM25;
|
||||||
|
chart.data.datasets[2].data = PM10;
|
||||||
|
chart.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//end fetch config
|
|
||||||
})
|
|
||||||
.catch(error => console.error('Error loading config.json:', error));
|
|
||||||
//end windows on load
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ header("Content-Type: application/json");
|
|||||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||||
header("Pragma: no-cache");
|
header("Pragma: no-cache");
|
||||||
|
|
||||||
|
$database_path = "/var/www/moduleair_pro_4g/sqlite/sensors.db";
|
||||||
|
|
||||||
$type=$_GET['type'];
|
$type=$_GET['type'];
|
||||||
|
|
||||||
if ($type == "get_npm_sqlite_data") {
|
if ($type == "get_npm_sqlite_data") {
|
||||||
$database_path = "/var/www/moduleair_pro_4g/sqlite/sensors.db";
|
|
||||||
//echo "Getting data from sqlite database";
|
//echo "Getting data from sqlite database";
|
||||||
try {
|
try {
|
||||||
$db = new PDO("sqlite:$database_path");
|
$db = new PDO("sqlite:$database_path");
|
||||||
@@ -25,6 +26,193 @@ if ($type == "get_npm_sqlite_data") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GETING data from config_table (SQLite DB)
|
||||||
|
if ($type == "get_config_sqlite") {
|
||||||
|
try {
|
||||||
|
$db = new PDO("sqlite:$database_path");
|
||||||
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
|
// Get all main configuration entries
|
||||||
|
$config_query = $db->query("SELECT key, value, type FROM config_table");
|
||||||
|
$config_data = $config_query->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Convert data types according to their 'type' field
|
||||||
|
$result = [];
|
||||||
|
foreach ($config_data as $item) {
|
||||||
|
$key = $item['key'];
|
||||||
|
$value = $item['value'];
|
||||||
|
$type = $item['type'];
|
||||||
|
|
||||||
|
// Convert value based on its type
|
||||||
|
switch ($type) {
|
||||||
|
case 'bool':
|
||||||
|
$parsed_value = ($value == '1' || $value == 'true') ? true : false;
|
||||||
|
break;
|
||||||
|
case 'int':
|
||||||
|
$parsed_value = intval($value);
|
||||||
|
break;
|
||||||
|
case 'float':
|
||||||
|
$parsed_value = floatval($value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$parsed_value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$key] = $parsed_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return JSON response
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode($result, JSON_PRETTY_PRINT);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// Return error as JSON
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//GETING data from config_scrips_table (SQLite DB)
|
||||||
|
if ($type == "get_config_scripts_sqlite") {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = new PDO("sqlite:$database_path");
|
||||||
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
|
// Get all main configuration entries
|
||||||
|
$config_query = $db->query("SELECT * FROM config_scripts_table");
|
||||||
|
$config_data = $config_query->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Convert data types according to their 'type' field
|
||||||
|
$result = [];
|
||||||
|
foreach ($config_data as $item) {
|
||||||
|
$script_path = $item['script_path'];
|
||||||
|
$enabled = $item['enabled'];
|
||||||
|
|
||||||
|
// Convert the enabled field to a proper boolean
|
||||||
|
$result[$script_path] = ($enabled == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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") {
|
||||||
|
$param = $_GET['param'] ?? null;
|
||||||
|
$value = $_GET['value'] ?? null;
|
||||||
|
|
||||||
|
if ($param === null || $value === null) {
|
||||||
|
echo json_encode(["error" => "Missing parameter or value"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//UPDATING the config_scripts table from SQLite DB
|
||||||
|
if ($type == "update_config_scripts_sqlite") {
|
||||||
|
$script_path = $_GET['param'] ?? null;
|
||||||
|
$enabled = $_GET['value'] ?? null;
|
||||||
|
|
||||||
|
if ($script_path === null || $enabled === null) {
|
||||||
|
echo json_encode(["error" => "Missing parameter or value"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 enabled FROM config_scripts_table WHERE script_path = :script_path");
|
||||||
|
$checkStmt->bindParam(':script_path', $script_path);
|
||||||
|
$checkStmt->execute();
|
||||||
|
$result = $checkStmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
// Convert enabled value to 0 or 1
|
||||||
|
$enabledValue = (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) ? 1 : 0;
|
||||||
|
|
||||||
|
// Update the enabled status
|
||||||
|
$updateStmt = $db->prepare("UPDATE config_scripts_table SET enabled = :enabled WHERE script_path = :script_path");
|
||||||
|
$updateStmt->bindParam(':enabled', $enabledValue, PDO::PARAM_INT);
|
||||||
|
$updateStmt->bindParam(':script_path', $script_path);
|
||||||
|
$updateStmt->execute();
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
"success" => true,
|
||||||
|
"message" => "Script configuration updated successfully",
|
||||||
|
"script_path" => $script_path,
|
||||||
|
"enabled" => (bool)$enabledValue
|
||||||
|
], JSON_UNESCAPED_SLASHES); // Prevent escaping forward slashes
|
||||||
|
} else {
|
||||||
|
echo json_encode([
|
||||||
|
"error" => "Script path not found in configuration",
|
||||||
|
"script_path" => $script_path
|
||||||
|
], JSON_UNESCAPED_SLASHES); // Prevent escaping forward slashes
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//old JSON way
|
||||||
if ($type == "update_config") {
|
if ($type == "update_config") {
|
||||||
echo "updating....";
|
echo "updating....";
|
||||||
$param=$_GET['param'];
|
$param=$_GET['param'];
|
||||||
|
|||||||
234
html/logs.html
234
html/logs.html
@@ -56,7 +56,9 @@
|
|||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
<div class="card" style="height: 80vh;">
|
<div class="card" style="height: 80vh;">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Master logs <button type="submit" class="btn btn-secondary btn-sm" onclick="clear_loopLogs()">Clear</button>
|
Master logs
|
||||||
|
<button type="submit" class="btn btn-secondary btn-sm" id="refresh-master-log">Refresh</button>
|
||||||
|
<button type="submit" class="btn btn-secondary btn-sm" onclick="clear_loopLogs()">Clear</button>
|
||||||
<span id="script_running"></span>
|
<span id="script_running"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body overflow-auto" id="card_loop_content">
|
<div class="card-body overflow-auto" id="card_loop_content">
|
||||||
@@ -69,6 +71,8 @@
|
|||||||
<div class="card" style="height: 80vh;">
|
<div class="card" style="height: 80vh;">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Boot logs
|
Boot logs
|
||||||
|
<button type="submit" class="btn btn-secondary btn-sm" id="refresh-boot-log">Refresh</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body overflow-auto" id="card_boot_content">
|
<div class="card-body overflow-auto" id="card_boot_content">
|
||||||
|
|
||||||
@@ -89,122 +93,158 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const elementsToLoad = [
|
const elementsToLoad = [
|
||||||
{ id: 'topbar', file: 'topbar.html' },
|
{ id: 'topbar', file: 'topbar.html' },
|
||||||
{ id: 'sidebar', file: 'sidebar.html' },
|
{ id: 'sidebar', file: 'sidebar.html' },
|
||||||
{ id: 'sidebar_mobile', file: 'sidebar.html' }
|
{ id: 'sidebar_mobile', file: 'sidebar.html' }
|
||||||
];
|
];
|
||||||
|
|
||||||
elementsToLoad.forEach(({ id, file }) => {
|
elementsToLoad.forEach(({ id, file }) => {
|
||||||
fetch(file)
|
fetch(file)
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const element = document.getElementById(id);
|
const element = document.getElementById(id);
|
||||||
if (element) {
|
if (element) {
|
||||||
element.innerHTML = data;
|
element.innerHTML = data;
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => console.error(`Error loading ${file}:`, error));
|
|
||||||
});
|
|
||||||
|
|
||||||
const loop_card_content = document.getElementById('card_loop_content');
|
|
||||||
const boot_card_content = document.getElementById('card_boot_content');
|
|
||||||
|
|
||||||
fetch('../logs/master.log')
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to fetch the log file.');
|
|
||||||
}
|
}
|
||||||
return response.text();
|
})
|
||||||
})
|
.catch(error => console.error(`Error loading ${file}:`, error));
|
||||||
.then((data) => {
|
});
|
||||||
const lines = data.split('\n');
|
|
||||||
|
|
||||||
// Format log content
|
const loop_card_content = document.getElementById('card_loop_content');
|
||||||
const formattedLog = lines
|
const boot_card_content = document.getElementById('card_boot_content');
|
||||||
.map((line) => line.trim()) // Remove extra whitespace
|
|
||||||
.filter((line) => line) // Remove empty lines
|
|
||||||
.join('<br>'); // Join formatted lines with line breaks
|
|
||||||
|
|
||||||
loop_card_content.innerHTML = `<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;">${formattedLog}</pre>`;
|
//Getting Master logs
|
||||||
loop_card_content.scrollTop = loop_card_content.scrollHeight; // Scroll to the bottom
|
console.log("Getting master logs");
|
||||||
|
displayLogFile('../logs/master.log', loop_card_content);
|
||||||
|
|
||||||
})
|
console.log("Getting app/boot logs");
|
||||||
.catch((error) => {
|
displayLogFile('../logs/app.log', boot_card_content);
|
||||||
console.error(error);
|
|
||||||
loop_card_content.textContent = 'Error loading log file.';
|
|
||||||
});
|
|
||||||
|
|
||||||
fetch('../logs/app.log')
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to fetch the log file.');
|
|
||||||
}
|
|
||||||
return response.text();
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
const lines = data.split('\n');
|
|
||||||
|
|
||||||
// Format log content
|
|
||||||
const formattedLog = lines
|
|
||||||
.map((line) => line.trim()) // Remove extra whitespace
|
|
||||||
.filter((line) => line) // Remove empty lines
|
|
||||||
.join('<br>'); // Join formatted lines with line breaks
|
|
||||||
|
|
||||||
boot_card_content.innerHTML = `<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;">${formattedLog}</pre>`;
|
|
||||||
boot_card_content.scrollTop = loop_card_content.scrollHeight; // Scroll to the bottom
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
boot_card_content.textContent = 'Error loading log file.';
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Setup master log with refresh button
|
||||||
|
setupLogRefreshButton('refresh-master-log', '../logs/master.log', 'card_loop_content', 3000);
|
||||||
|
|
||||||
|
// Setup boot log with refresh button
|
||||||
|
setupLogRefreshButton('refresh-boot-log', '../logs/app.log', 'card_boot_content', 300);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
|
||||||
getModem_busy_status();
|
getModem_busy_status();
|
||||||
setInterval(getModem_busy_status, 2000);
|
setInterval(getModem_busy_status, 2000);
|
||||||
|
|
||||||
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
|
//NEW way to get config (SQLite)
|
||||||
.then(response => response.json()) // Parse response as JSON
|
$.ajax({
|
||||||
.then(data => {
|
url: 'launcher.php?type=get_config_sqlite',
|
||||||
console.log("Getting config file (onload)");
|
dataType:'json',
|
||||||
//get device ID
|
//dataType: 'json', // Specify that you expect a JSON response
|
||||||
const deviceID = data.deviceID.trim().toUpperCase();
|
method: 'GET', // Use GET or POST depending on your needs
|
||||||
// document.getElementById('pageTitle_plus_ID').innerText = 'token: ' + deviceID;
|
success: function(response) {
|
||||||
//get device Name
|
console.log("Getting SQLite config table:");
|
||||||
const deviceName = data.deviceName;
|
console.log(response);
|
||||||
|
|
||||||
const elements = document.querySelectorAll('.sideBar_sensorName');
|
|
||||||
elements.forEach((element) => {
|
|
||||||
element.innerText = deviceName;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//get local RTC
|
//device name_side bar
|
||||||
$.ajax({
|
const elements = document.querySelectorAll('.sideBar_sensorName');
|
||||||
url: 'launcher.php?type=RTC_time',
|
elements.forEach((element) => {
|
||||||
dataType: 'text', // Specify that you expect a JSON response
|
element.innerText = response.deviceName;
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
},
|
||||||
.catch(error => console.error('Error loading config.json:', error));
|
error: function(xhr, status, error) {
|
||||||
}
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});//end AJAX
|
||||||
|
|
||||||
|
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayLogFile(logFilePath, containerElement, scrollToBottom = true, maxLines = 0) {
|
||||||
|
// Show loading indicator
|
||||||
|
containerElement.innerHTML = '<div class="text-center"><i>Loading log file...</i></div>';
|
||||||
|
|
||||||
|
return fetch(logFilePath)
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch the log file: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return response.text();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
// Split the log into lines
|
||||||
|
let lines = data.split('\n');
|
||||||
|
|
||||||
|
// Apply max lines limit if specified
|
||||||
|
if (maxLines > 0 && lines.length > maxLines) {
|
||||||
|
lines = lines.slice(-maxLines); // Get only the last N lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format log content
|
||||||
|
const formattedLog = lines
|
||||||
|
.map((line) => line.trim()) // Remove extra whitespace
|
||||||
|
.filter((line) => line) // Remove empty lines
|
||||||
|
.join('<br>'); // Join formatted lines with line breaks
|
||||||
|
|
||||||
|
// Display the formatted log
|
||||||
|
containerElement.innerHTML = `<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;">${formattedLog}</pre>`;
|
||||||
|
|
||||||
|
// Scroll to bottom if requested
|
||||||
|
if (scrollToBottom) {
|
||||||
|
containerElement.scrollTop = containerElement.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return formattedLog; // Return the formatted log in case the caller needs it
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(`Error loading log file ${logFilePath}:`, error);
|
||||||
|
containerElement.innerHTML = `<div class="text-danger">Error loading log file: ${error.message}</div>`;
|
||||||
|
throw error; // Re-throw the error for the caller to handle if needed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up a refresh button for a log file
|
||||||
|
* @param {string} buttonId - ID of the button element
|
||||||
|
* @param {string} logFilePath - Path to the log file
|
||||||
|
* @param {string} containerId - ID of the container to display the log in
|
||||||
|
* @param {number} maxLines - Maximum number of lines to display (0 for all)
|
||||||
|
*/
|
||||||
|
function setupLogRefreshButton(buttonId, logFilePath, containerId, maxLines = 0) {
|
||||||
|
console.log("Refreshing logs");
|
||||||
|
|
||||||
|
const button = document.getElementById(buttonId);
|
||||||
|
const container = document.getElementById(containerId);
|
||||||
|
|
||||||
|
if (!button || !container) {
|
||||||
|
console.error('Button or container element not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial load
|
||||||
|
displayLogFile(logFilePath, container, true, maxLines);
|
||||||
|
|
||||||
|
// Set up button click handler
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
displayLogFile(logFilePath, container, true, maxLines);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function clear_loopLogs(){
|
function clear_loopLogs(){
|
||||||
console.log("Clearing loop logs");
|
console.log("Clearing loop logs");
|
||||||
|
|
||||||
|
|||||||
@@ -286,36 +286,51 @@
|
|||||||
<script src="assets/js/bootstrap.bundle.js"></script>
|
<script src="assets/js/bootstrap.bundle.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const elementsToLoad = [
|
const elementsToLoad = [
|
||||||
{ id: 'topbar', file: 'topbar.html' },
|
{ id: 'topbar', file: 'topbar.html' },
|
||||||
{ id: 'sidebar', file: 'sidebar.html' },
|
{ id: 'sidebar', file: 'sidebar.html' },
|
||||||
{ id: 'sidebar_mobile', file: 'sidebar.html' }
|
{ id: 'sidebar_mobile', file: 'sidebar.html' }
|
||||||
];
|
];
|
||||||
|
|
||||||
elementsToLoad.forEach(({ id, file }) => {
|
elementsToLoad.forEach(({ id, file }) => {
|
||||||
fetch(file)
|
fetch(file)
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const element = document.getElementById(id);
|
const element = document.getElementById(id);
|
||||||
if (element) {
|
if (element) {
|
||||||
element.innerHTML = data;
|
element.innerHTML = data;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => console.error(`Error loading ${file}:`, error));
|
||||||
|
});
|
||||||
|
|
||||||
|
//NEW way to get data from 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);
|
||||||
|
// Set checkbox state based on the response data
|
||||||
|
const check_modem_configMode = document.getElementById("check_modem_configMode");
|
||||||
|
if (check_modem_configMode) {
|
||||||
|
check_modem_configMode.checked = response.modem_config_mode;
|
||||||
|
console.log("Modem configuration: " + response.modem_config_mode);
|
||||||
|
} else {
|
||||||
|
console.error("Checkbox element not found");
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(error => console.error(`Error loading ${file}:`, error));
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
|
|
||||||
.then(response => response.json()) // Parse response as JSON
|
|
||||||
.then(data => {
|
|
||||||
console.log("Getting config file (onload)");
|
|
||||||
//modem config mode
|
|
||||||
const check_modem_configMode = document.getElementById("check_modem_configMode");
|
|
||||||
check_modem_configMode.checked = data.modem_config_mode;
|
|
||||||
console.log("Modem configuration: " + data.modem_config_mode);
|
|
||||||
|
|
||||||
})
|
}); //END DOMContentLoaded
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
function getData_saraR4(port, command, timeout){
|
function getData_saraR4(port, command, timeout){
|
||||||
console.log("Data from SaraR4");
|
console.log("Data from SaraR4");
|
||||||
|
|||||||
@@ -86,6 +86,167 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//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 = `
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Port UART 3
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">NextPM</h5>
|
||||||
|
<p class="card-text">Capteur particules fines.</p>
|
||||||
|
<button class="btn btn-primary" onclick="getNPM_values('ttyAMA3')">Get Data</button>
|
||||||
|
<br>
|
||||||
|
<div id="loading_ttyAMA3" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
||||||
|
<table class="table table-striped-columns">
|
||||||
|
<tbody id="data-table-body_ttyAMA3"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
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 = `
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Port I2C
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">BME280 Temp/Hum sensor</h5>
|
||||||
|
<p class="card-text">Capteur température et humidité sur le port I2C.</p>
|
||||||
|
<button class="btn btn-primary mb-1" onclick="getBME280_values()">Get Data</button>
|
||||||
|
<br>
|
||||||
|
<div id="loading_BME280" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
||||||
|
<table class="table table-striped-columns">
|
||||||
|
<tbody id="data-table-body_BME280"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
container.innerHTML += i2C_BME_HTML; // Add the I2C card if condition is met
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//creates CO2 card
|
||||||
|
if (response["MH-Z19/write_data.py"]) {
|
||||||
|
const MH_Z19 = `
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Port UART 4
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">CO2 Sensor</h5>
|
||||||
|
<p class="card-text">Capteur de Dioxyde de carbone</p>
|
||||||
|
<button class="btn btn-primary mb-1" onclick="getco2_values()">Get Data</button>
|
||||||
|
<br>
|
||||||
|
<div id="loading_co2" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
||||||
|
<table class="table table-striped-columns">
|
||||||
|
<tbody id="data-table-body_co2"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
container.innerHTML += MH_Z19; // Add the I2C card if condition is met
|
||||||
|
}
|
||||||
|
|
||||||
|
//creates CO2 card
|
||||||
|
if (response["sensirion/SFA30_read.py"]) {
|
||||||
|
const MH_Z19 = `
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Port UART 4
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">CH₂O Sensor</h5>
|
||||||
|
<p class="card-text">Capteur de Formaldehyde </p>
|
||||||
|
<button class="btn btn-primary mb-1" onclick="getSFA30_values()">Get Data</button>
|
||||||
|
<br>
|
||||||
|
<div id="loading_SFA30" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
||||||
|
<table class="table table-striped-columns">
|
||||||
|
<tbody id="data-table-body_SFA30"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
container.innerHTML += MH_Z19; // Add the I2C card if condition is met
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error('AJAX request failed:', status, error);
|
||||||
|
}
|
||||||
|
});//end AJAX
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function getNPM_values(port){
|
function getNPM_values(port){
|
||||||
console.log("Data from NPM (port "+port+"):");
|
console.log("Data from NPM (port "+port+"):");
|
||||||
$("#loading_"+port).show();
|
$("#loading_"+port).show();
|
||||||
@@ -215,7 +376,7 @@ function getNoise_values(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getco2_values() {
|
function getco2_values() {
|
||||||
console.log("Data from UART 4:");
|
console.log("Data from UART 4:");
|
||||||
$("#loading_co2").show();
|
$("#loading_co2").show();
|
||||||
|
|
||||||
@@ -301,143 +462,7 @@ 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;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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 = `
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
Port UART ${port.replace('ttyAMA', '')}
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">NextPM ${String.fromCharCode(65 + index)}</h5>
|
|
||||||
<p class="card-text">Capteur particules fines.</p>
|
|
||||||
<button class="btn btn-primary" onclick="getNPM_values('${port}')">Get Data</button>
|
|
||||||
<div id="loading_${port}" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
||||||
<table class="table table-striped-columns">
|
|
||||||
<tbody id="data-table-body_${port}"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
container.innerHTML += cardHTML; // Ajouter la carte au conteneur
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//creates i2c BME280 card
|
|
||||||
if (data.i2c_BME) {
|
|
||||||
const i2C_BME_HTML = `
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
Port I2C
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">BME280 Temp/Hum sensor</h5>
|
|
||||||
<p class="card-text">Capteur température et humidité sur le port I2C.</p>
|
|
||||||
<button class="btn btn-primary mb-1" onclick="getBME280_values()">Get Data</button>
|
|
||||||
<br>
|
|
||||||
<div id="loading_BME280" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
||||||
<table class="table table-striped-columns">
|
|
||||||
<tbody id="data-table-body_BME280"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
container.innerHTML += i2C_BME_HTML; // Add the I2C card if condition is met
|
|
||||||
}
|
|
||||||
|
|
||||||
//creates i2c sound card
|
|
||||||
if (data.i2C_sound) {
|
|
||||||
const i2C_HTML = `
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
Port I2C
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">Decibel Meter</h5>
|
|
||||||
<p class="card-text">Capteur bruit sur le port I2C.</p>
|
|
||||||
<button class="btn btn-primary mb-1" onclick="getNoise_values()">Get Data</button>
|
|
||||||
<br>
|
|
||||||
<button class="btn btn-success" onclick="startNoise()">Start recording</button>
|
|
||||||
<button class="btn btn-danger" onclick="stopNoise()">Stop recording</button>
|
|
||||||
<div id="loading_noise" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
||||||
<table class="table table-striped-columns">
|
|
||||||
<tbody id="data-table-body_noise"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
container.innerHTML += i2C_HTML; // Add the I2C card if condition is met
|
|
||||||
}
|
|
||||||
|
|
||||||
//creates CO2 card
|
|
||||||
if (data.CO2_serial) {
|
|
||||||
const MH_Z19 = `
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
Port UART 4
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">CO2 Sensor</h5>
|
|
||||||
<p class="card-text">Capteur de Dioxyde de carbone</p>
|
|
||||||
<button class="btn btn-primary mb-1" onclick="getco2_values()">Get Data</button>
|
|
||||||
<br>
|
|
||||||
<div id="loading_co2" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
||||||
<table class="table table-striped-columns">
|
|
||||||
<tbody id="data-table-body_co2"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
|
|
||||||
container.innerHTML += MH_Z19; // Add the I2C card if condition is met
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(error => console.error('Error loading config.json:', error));
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ SCRIPTS = [
|
|||||||
("NPM/get_data_modbus_v3.py", 10, 0), # Get NPM data (modbus 5 channels) every 10s
|
("NPM/get_data_modbus_v3.py", 10, 0), # Get NPM data (modbus 5 channels) every 10s
|
||||||
("MH-Z19/write_data.py", 10, 0), # Get Envea data every 10s
|
("MH-Z19/write_data.py", 10, 0), # Get Envea data every 10s
|
||||||
("loop/SARA_send_data_v2.py", 60, 1), # Send data every 60 seconds, with 1s delay
|
("loop/SARA_send_data_v2.py", 60, 1), # Send data every 60 seconds, with 1s delay
|
||||||
|
("sensirion/SFA30_read.py", 10, 0), # Send data every 60 seconds, with 1s delay
|
||||||
("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
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,14 @@ CREATE TABLE IF NOT EXISTS data_CO2 (
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
# Create a table sensirion SFA30
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS data_sensirionSFA30 (
|
||||||
|
timestamp TEXT,
|
||||||
|
CH2O INTEGER
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
# Create a table BME280
|
# Create a table BME280
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS data_BME280 (
|
CREATE TABLE IF NOT EXISTS data_BME280 (
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ script_configs = [
|
|||||||
("BME280/get_data_v2.py", False),
|
("BME280/get_data_v2.py", False),
|
||||||
("envea/read_value_v2.py", False),
|
("envea/read_value_v2.py", False),
|
||||||
("MH-Z19/write_data.py", True),
|
("MH-Z19/write_data.py", True),
|
||||||
("windMeter/read.py", False),
|
("sensirion/SFA30_read.py", False),
|
||||||
("sqlite/flush_old_data.py", True)
|
("sqlite/flush_old_data.py", True)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user