diff --git a/NPM/get_data_modbus_v3.py b/NPM/get_data_modbus_v3.py index c972bb6..120688a 100755 --- a/NPM/get_data_modbus_v3.py +++ b/NPM/get_data_modbus_v3.py @@ -40,6 +40,9 @@ import crcmod import sqlite3 import time +# Dry-run mode: print JSON output without writing to database +dry_run = "--dry-run" in sys.argv + # Connect to the SQLite database conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db") cursor = conn.cursor() @@ -207,15 +210,29 @@ except Exception as e: # Variables already set to -1 at the beginning finally: - # Always save data to database, even if all values are -1 - cursor.execute(''' - 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)) + 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(''' + 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)) - cursor.execute(''' - INSERT INTO data_NPM (timestamp,PM1, PM25, PM10, temp_npm, hum_npm, npm_status) VALUES (?,?,?,?,?,?,?)''' - , (rtc_time_str, pm1_10s, pm25_10s, pm10_10s, temperature, relative_humidity, npm_status)) + cursor.execute(''' + INSERT INTO data_NPM (timestamp,PM1, PM25, PM10, temp_npm, hum_npm, npm_status) VALUES (?,?,?,?,?,?,?)''' + , (rtc_time_str, pm1_10s, pm25_10s, pm10_10s, temperature, relative_humidity, npm_status)) + + # Commit and close the connection + conn.commit() - # Commit and close the connection - conn.commit() conn.close() \ No newline at end of file diff --git a/VERSION b/VERSION index 26ca594..4cda8f1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.1 +1.5.2 diff --git a/changelog.json b/changelog.json index 0e3e75d..646afc5 100644 --- a/changelog.json +++ b/changelog.json @@ -1,5 +1,25 @@ { "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", "date": "2026-03-18", diff --git a/html/launcher.php b/html/launcher.php index 6557b3c..ccb19af 100755 --- a/html/launcher.php +++ b/html/launcher.php @@ -805,8 +805,7 @@ if ($type == "reboot") { } if ($type == "npm") { - $port=$_GET['port']; - $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data.py ' . $port; + $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_v3.py --dry-run'; $output = shell_exec($command); echo $output; } diff --git a/html/sensors.html b/html/sensors.html index 3729264..1d0367f 100755 --- a/html/sensors.html +++ b/html/sensors.html @@ -117,54 +117,79 @@ $("#loading_" + port).show(); $.ajax({ - url: 'launcher.php?type=npm&port=' + port, - dataType: 'json', // Specify that you expect a JSON response - method: 'GET', // Use GET or POST depending on your needs + url: 'launcher.php?type=npm', + dataType: 'json', + method: 'GET', success: function (response) { console.log(response); const tableBody = document.getElementById("data-table-body_" + port); tableBody.innerHTML = ""; $("#loading_" + port).hide(); - // Create an array of the desired keys - const keysToShow = ["PM1", "PM25", "PM10", "message"]; - // Error messages mapping - const errorMessages = { - "notReady": "Sensor is not ready", - "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]; + + // PM values + const pmKeys = ["PM1", "PM25", "PM10"]; + pmKeys.forEach(key => { + if (response[key] !== undefined) { $("#data-table-body_" + port).append(` - - ${key} - ${value} µg/m³ - - `); + + ${key} + ${response[key]} µg/m³ + + `); } }); - // Check for errors and add them to the table - Object.keys(errorMessages).forEach(errorKey => { - if (response[errorKey] === 1) { - $("#data-table-body_" + port).append(` - - ${errorKey} - ⚠ ${errorMessages[errorKey]} - - `); - } - }); + // Temperature & humidity + if (response.temperature !== undefined) { + $("#data-table-body_" + port).append(` + Temperature${response.temperature} °C + `); + } + if (response.humidity !== undefined) { + $("#data-table-body_" + port).append(` + Humidity${response.humidity} % + `); + } + + // 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(` + + Status + ${statusText} + + `); + + // 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(` + + + ⚠ ${label} + + `); + } + }); + } }, error: function (xhr, status, error) { console.error('AJAX request failed:', status, error); + $("#loading_" + port).hide(); } }); }