diff --git a/MH-Z19/write_data.py b/MH-Z19/write_data.py
index f669560..ecab40b 100755
--- a/MH-Z19/write_data.py
+++ b/MH-Z19/write_data.py
@@ -24,20 +24,7 @@ import sqlite3
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
-def load_config(config_file):
- 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
+mh_z19_port = "/dev/ttyAMA4" #port du NPM solo
ser = serial.Serial(
port=mh_z19_port,
diff --git a/NPM/get_data_modbus_v3.py b/NPM/get_data_modbus_v3.py
index b766141..bacbad2 100755
--- a/NPM/get_data_modbus_v3.py
+++ b/NPM/get_data_modbus_v3.py
@@ -42,19 +42,8 @@ import time
conn = sqlite3.connect("/var/www/moduleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()
-def load_config(config_file):
- 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 {}
+npm_solo_port = "/dev/ttyAMA3" #port du NPM solo
-# 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
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
diff --git a/html/admin.html b/html/admin.html
index aa6c47c..026dcd6 100755
--- a/html/admin.html
+++ b/html/admin.html
@@ -59,48 +59,9 @@
@@ -117,12 +121,6 @@
Clock
-
-
-
-
@@ -155,12 +153,25 @@
Updates
-
-
+
+
+
+
+
+
+
+
+ Hello, world! This is a toast message.
+
+
+
+
+
+
@@ -193,112 +204,248 @@
});
});
+//end document.addEventListener
+
+
+/*
+ ___ _ _
+ / _ \ _ __ | | ___ __ _ __| |
+ | | | | '_ \| | / _ \ / _` |/ _` |
+ | |_| | | | | |__| (_) | (_| | (_| |
+ \___/|_| |_|_____\___/ \__,_|\__,_|
+
+*/
+
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
- const deviceName = data.deviceName;
-
- console.log("Device Name: " + deviceName);
- console.log("Device ID: " + deviceID);
-
-
-
- const elements = document.querySelectorAll('.sideBar_sensorName');
- elements.forEach((element) => {
- element.innerText = deviceName;
- });
-
- //get BME check
- const checkbox = document.getElementById("check_bme280");
- checkbox.checked = data["BME280/get_data_v2.py"];
-
- //get NPM-5channels check
- const checkbox_NPM_5channels = document.getElementById("check_NPM_5channels");
- checkbox_NPM_5channels.checked = data["NextPM_5channels"];
-
- //get sonde Envea check
- const checkbox_envea = document.getElementById("check_envea");
- checkbox_envea.checked = data["envea/read_value_v2.py"];
-
- //get RTC check
- const checkbox_RTC = document.getElementById("check_RTC");
- checkbox_RTC.checked = data.i2c_RTC;
+//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
+ const deviceName = document.getElementById("device_name");
+ 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;
+
- //device name
- const device_name = document.getElementById("device_name");
- device_name.value = data.deviceName;
- //device ID
- const device_ID = document.getElementById("device_ID");
- device_ID.value = data.deviceID.toUpperCase();
+ },
+ 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);
- //get system time and RTC module
- $.ajax({
- 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;
+ const checkbox_NPM = document.getElementById("check_NPM");
+ const checkbox_bme = document.getElementById("check_bme280");
+ const checkbox_CO2 = document.getElementById("check_CO2");
+ const checkbox_SFA30 = document.getElementById("check_sensirionSFA30");
- // Get the time difference
- const timeDiff = response.time_difference_seconds;
+ checkbox_NPM.checked = response["NPM/get_data_modbus_v3.py"];
+ checkbox_bme.checked = response["BME280/get_data_v2.py"];
+ checkbox_SFA30.checked = response["sensirion/SFA30_read.py"];
+ checkbox_CO2.checked = response["MH-Z19/write_data.py"];
- // Reference to the alert container
- const alertContainer = document.getElementById("alert_container");
+ //si sonde envea is true
+ if (response["envea/read_value_v2.py"]) {
+ add_sondeEnveaContainer();
+
+ }
+ },
+ error: function(xhr, status, error) {
+ console.error('AJAX request failed:', status, error);
+ }
+ });//end AJAX
- // Remove any previous alert
- alertContainer.innerHTML = "";
+//get system time and RTC module
+$.ajax({
+ 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;
- // Add an alert based on time difference
- if (typeof timeDiff === "number") {
- if (timeDiff >= 0 && timeDiff <= 10) {
- alertContainer.innerHTML = `
-
- RTC and system time are in sync (Difference: ${timeDiff} sec).
-
`;
- } else if (timeDiff > 10) {
- alertContainer.innerHTML = `
-
- RTC time is out of sync! (Difference: ${timeDiff} sec).
-
`;
- }
- }
- },
- error: function(xhr, status, error) {
- console.error('AJAX request failed:', status, error);
+ // Get the time difference
+ const timeDiff = response.time_difference_seconds;
+
+ // Reference to the alert container
+ const alertContainer = document.getElementById("alert_container");
+
+ // Remove any previous alert
+ alertContainer.innerHTML = "";
+
+ // Add an alert based on time difference
+ if (typeof timeDiff === "number") {
+ if (timeDiff >= 0 && timeDiff <= 10) {
+ alertContainer.innerHTML = `
+
+ RTC and system time are in sync (Difference: ${timeDiff} sec).
+
`;
+ } else if (timeDiff > 10) {
+ alertContainer.innerHTML = `
+
+ RTC time is out of sync! (Difference: ${timeDiff} sec).
+
`;
}
- });
+ }
+ },
+ 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);
- }
- });
+//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);
+ }
+ });//end ajax
- })
- .catch(error => console.error('Error loading config.json:', error));
- }
+} //end windows on load
+
+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 = `
+ Success!
+ Parameter: ${response.param || param}
+ Value: ${response.value || checked}
+ ${response.message || ''}
+ `;
+ } else {
+ // Error message
+ toastLiveExample.classList.remove('text-bg-success');
+ toastLiveExample.classList.add('text-bg-danger');
+
+ formattedMessage = `
+ Error!
+ ${response.error || 'Unknown error'}
+ 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 = `
+ Success!
+ Parameter: ${response.script_path || param}
+ Value: ${response.enabled !== undefined ? response.enabled : value}
+ ${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 = `
+ Error!
+ ${response.error || 'Unknown error'}
+ 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){
diff --git a/html/database.html b/html/database.html
index 4eecb64..9a8c24f 100755
--- a/html/database.html
+++ b/html/database.html
@@ -151,42 +151,48 @@
- 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
- const deviceName = data.deviceName;
-
- const elements = document.querySelectorAll('.sideBar_sensorName');
- elements.forEach((element) => {
- element.innerText = deviceName;
- });
+window.onload = function() {
+
+ //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
- //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);
- }
- });
+ //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);
+ }
+ });
- })
- .catch(error => console.error('Error loading config.json:', error));
- }
+
+}
diff --git a/html/index.html b/html/index.html
index 81c8716..570d3fc 100755
--- a/html/index.html
+++ b/html/index.html
@@ -135,296 +135,296 @@
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;
+ //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
-
- //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);
+ }
+ });
- //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);
- }
- });
+ //get database size
+ $.ajax({
+ 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);
+
+ if (response.size_megabytes !== undefined) {
+ // Extract and format the size in MB
+ const databaseSizeMB = response.size_megabytes + " MB";
- //get database size
- $.ajax({
- 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);
-
- if (response.size_megabytes !== undefined) {
- // Extract and format the size in MB
- const databaseSizeMB = response.size_megabytes + " MB";
+ // Update the HTML element with the database size
+ const databaseSizeElement = document.getElementById("database_size");
+ databaseSizeElement.textContent = databaseSizeMB;
- // Update the HTML element with the database size
- const databaseSizeElement = document.getElementById("database_size");
- databaseSizeElement.textContent = databaseSizeMB;
-
- 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);
- }
- });
+ 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(/(? 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();
+ },
+ 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;
- //end fetch config
- })
- .catch(error => console.error('Error loading config.json:', error));
- //end windows on load
+ 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();
+ }
+ }
+
+
}
diff --git a/html/launcher.php b/html/launcher.php
index a3a9f1b..0f7c84d 100755
--- a/html/launcher.php
+++ b/html/launcher.php
@@ -4,10 +4,11 @@ header("Content-Type: application/json");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Pragma: no-cache");
+$database_path = "/var/www/moduleair_pro_4g/sqlite/sensors.db";
+
$type=$_GET['type'];
if ($type == "get_npm_sqlite_data") {
- $database_path = "/var/www/moduleair_pro_4g/sqlite/sensors.db";
//echo "Getting data from sqlite database";
try {
$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") {
echo "updating....";
$param=$_GET['param'];
diff --git a/html/logs.html b/html/logs.html
index 7cb126d..24107b3 100755
--- a/html/logs.html
+++ b/html/logs.html
@@ -56,7 +56,9 @@