v1.5.2: page capteurs NPM via get_data_modbus_v3.py --dry-run
- NPM: mode --dry-run (print JSON sans ecriture en base) - launcher.php: endpoint npm appelle get_data_modbus_v3.py --dry-run - sensors.html: affichage PM + temp + humidite + status NPM decode - Suppression unite ug/m3 sur le champ status Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,9 @@ import crcmod
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
# Dry-run mode: print JSON output without writing to database
|
||||||
|
dry_run = "--dry-run" in sys.argv
|
||||||
|
|
||||||
# Connect to the SQLite database
|
# Connect to the SQLite database
|
||||||
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
@@ -207,7 +210,20 @@ except Exception as e:
|
|||||||
# Variables already set to -1 at the beginning
|
# Variables already set to -1 at the beginning
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# Always save data to database, even if all values are -1
|
if dry_run:
|
||||||
|
# Print JSON output without writing to database
|
||||||
|
result = {
|
||||||
|
"PM1": pm1_10s,
|
||||||
|
"PM25": pm25_10s,
|
||||||
|
"PM10": pm10_10s,
|
||||||
|
"temperature": temperature,
|
||||||
|
"humidity": relative_humidity,
|
||||||
|
"npm_status": npm_status,
|
||||||
|
"npm_status_hex": f"0x{npm_status:02X}"
|
||||||
|
}
|
||||||
|
print(json.dumps(result))
|
||||||
|
else:
|
||||||
|
# Always save data to database, even if all values are 0
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO data_NPM_5channels (timestamp,PM_ch1, PM_ch2, PM_ch3, PM_ch4, PM_ch5) VALUES (?,?,?,?,?,?)'''
|
INSERT INTO data_NPM_5channels (timestamp,PM_ch1, PM_ch2, PM_ch3, PM_ch4, PM_ch5) VALUES (?,?,?,?,?,?)'''
|
||||||
, (rtc_time_str, channel_1, channel_2, channel_3, channel_4, channel_5))
|
, (rtc_time_str, channel_1, channel_2, channel_3, channel_4, channel_5))
|
||||||
@@ -218,4 +234,5 @@ finally:
|
|||||||
|
|
||||||
# Commit and close the connection
|
# Commit and close the connection
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -1,5 +1,25 @@
|
|||||||
{
|
{
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "1.5.2",
|
||||||
|
"date": "2026-03-18",
|
||||||
|
"changes": {
|
||||||
|
"features": [
|
||||||
|
"Page capteurs: lecture NPM via get_data_modbus_v3.py --dry-run (meme script que le timer)",
|
||||||
|
"Page capteurs: affichage temperature et humidite interne du NPM",
|
||||||
|
"Page capteurs: decodage npm_status avec flags d'erreur individuels"
|
||||||
|
],
|
||||||
|
"improvements": [
|
||||||
|
"NPM get_data_modbus_v3.py: mode --dry-run (print JSON sans ecriture en base)",
|
||||||
|
"Page capteurs: status NPM affiche en vert (OK) ou orange/rouge (erreurs decodees)"
|
||||||
|
],
|
||||||
|
"fixes": [
|
||||||
|
"Page capteurs: suppression unite ug/m3 sur le champ message/status"
|
||||||
|
],
|
||||||
|
"compatibility": []
|
||||||
|
},
|
||||||
|
"notes": "La page capteurs utilise maintenant le meme script Modbus que le timer systemd, en mode dry-run pour eviter les conflits d'ecriture SQLite. Le status NPM est decode bit par bit."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"date": "2026-03-18",
|
"date": "2026-03-18",
|
||||||
|
|||||||
@@ -805,8 +805,7 @@ if ($type == "reboot") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($type == "npm") {
|
if ($type == "npm") {
|
||||||
$port=$_GET['port'];
|
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_v3.py --dry-run';
|
||||||
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data.py ' . $port;
|
|
||||||
$output = shell_exec($command);
|
$output = shell_exec($command);
|
||||||
echo $output;
|
echo $output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,54 +117,79 @@
|
|||||||
$("#loading_" + port).show();
|
$("#loading_" + port).show();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'launcher.php?type=npm&port=' + port,
|
url: 'launcher.php?type=npm',
|
||||||
dataType: 'json', // Specify that you expect a JSON response
|
dataType: 'json',
|
||||||
method: 'GET', // Use GET or POST depending on your needs
|
method: 'GET',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
console.log(response);
|
console.log(response);
|
||||||
const tableBody = document.getElementById("data-table-body_" + port);
|
const tableBody = document.getElementById("data-table-body_" + port);
|
||||||
tableBody.innerHTML = "";
|
tableBody.innerHTML = "";
|
||||||
|
|
||||||
$("#loading_" + port).hide();
|
$("#loading_" + port).hide();
|
||||||
// Create an array of the desired keys
|
|
||||||
const keysToShow = ["PM1", "PM25", "PM10", "message"];
|
// PM values
|
||||||
// Error messages mapping
|
const pmKeys = ["PM1", "PM25", "PM10"];
|
||||||
const errorMessages = {
|
pmKeys.forEach(key => {
|
||||||
"notReady": "Sensor is not ready",
|
if (response[key] !== undefined) {
|
||||||
"fanError": "Fan malfunction detected",
|
|
||||||
"laserError": "Laser malfunction detected",
|
|
||||||
"heatError": "Heating system error",
|
|
||||||
"t_rhError": "Temperature/Humidity sensor error",
|
|
||||||
"memoryError": "Memory failure detected",
|
|
||||||
"degradedState": "Sensor in degraded state"
|
|
||||||
};
|
|
||||||
// Add only the specified elements to the table
|
|
||||||
keysToShow.forEach(key => {
|
|
||||||
if (response[key] !== undefined) { // Check if the key exists in the response
|
|
||||||
const value = response[key];
|
|
||||||
$("#data-table-body_" + port).append(`
|
$("#data-table-body_" + port).append(`
|
||||||
<tr>
|
<tr>
|
||||||
<td>${key}</td>
|
<td>${key}</td>
|
||||||
<td>${value} µg/m³</td>
|
<td>${response[key]} µg/m³</td>
|
||||||
</tr>
|
</tr>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for errors and add them to the table
|
// Temperature & humidity
|
||||||
Object.keys(errorMessages).forEach(errorKey => {
|
if (response.temperature !== undefined) {
|
||||||
if (response[errorKey] === 1) {
|
$("#data-table-body_" + port).append(`
|
||||||
|
<tr><td>Temperature</td><td>${response.temperature} °C</td></tr>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
if (response.humidity !== undefined) {
|
||||||
|
$("#data-table-body_" + port).append(`
|
||||||
|
<tr><td>Humidity</td><td>${response.humidity} %</td></tr>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NPM status decoded
|
||||||
|
if (response.npm_status !== undefined) {
|
||||||
|
const status = response.npm_status;
|
||||||
|
const statusText = status === 0 ? "OK" : response.npm_status_hex;
|
||||||
|
const statusColor = status === 0 ? "green" : "orange";
|
||||||
|
$("#data-table-body_" + port).append(`
|
||||||
|
<tr>
|
||||||
|
<td>Status</td>
|
||||||
|
<td style="color: ${statusColor}; font-weight: bold;">${statusText}</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Decode individual error bits
|
||||||
|
const statusFlags = {
|
||||||
|
0x01: "Sleep mode",
|
||||||
|
0x02: "Degraded mode",
|
||||||
|
0x04: "Not ready",
|
||||||
|
0x08: "Heater error",
|
||||||
|
0x10: "THP sensor error",
|
||||||
|
0x20: "Fan error",
|
||||||
|
0x40: "Memory error",
|
||||||
|
0x80: "Laser error"
|
||||||
|
};
|
||||||
|
Object.entries(statusFlags).forEach(([mask, label]) => {
|
||||||
|
if (status & mask) {
|
||||||
$("#data-table-body_" + port).append(`
|
$("#data-table-body_" + port).append(`
|
||||||
<tr class="error-row">
|
<tr class="error-row">
|
||||||
<td><b>${errorKey}</b></td>
|
<td></td>
|
||||||
<td style="color: red;">⚠ ${errorMessages[errorKey]}</td>
|
<td style="color: red;">⚠ ${label}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
console.error('AJAX request failed:', status, error);
|
console.error('AJAX request failed:', status, error);
|
||||||
|
$("#loading_" + port).hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user