Le script get_data.py retourne maintenant toujours du JSON, meme en cas
d'erreur (port serie, absence de donnees). Cote web, les erreurs sont
affichees proprement dans la carte capteur.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Scripts MH-Z19/get_data.py (lecture standalone) et write_data.py (écriture SQLite)
- Table data_MHZ19, config MHZ19, cleanup et service systemd (120s)
- Web UI : carte test sensors, checkbox admin, boutons database + CSV download
- SARA_send_data_v2.py non modifié (sera fait dans un second temps)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Le script dans topbar.html ne s'exécutait pas car innerHTML ignore les
balises <script>. Déplacé la logique dans un fichier JS séparé
(topbar-logo.js) avec MutationObserver pour détecter l'insertion du topbar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Le logo ModuleAir n'était pas suivi par git, empêchant
l'affichage sur les capteurs configurés en ModuleAir Pro.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each table row in the stats card now has a download button that exports
the entire table as CSV with proper column headers, generated server-side.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show table info (entry count, oldest/newest dates, total DB size) in a
new card on the database page, with auto-refresh and i18n support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add VERSION file (1.0.0) and changelog.json for firmware tracking
- Add device_type config param (nebuleair_pro default, backward compatible via INSERT OR IGNORE)
- Add device_type select in admin.html Protected Settings
- Add version badge and changelog modal in Updates section
- Add get_firmware_version and get_changelog PHP endpoints
- Display firmware version in update_firmware.sh after git pull
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sensor tests (NPM, BME280, Noise, Envea) now run first, followed by
communication tests (WiFi, Modem, SIM, Signal, Network) with a
visual separator between the two sections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a "Firmware Version" button next to "Get Data" in the NextPM card
that calls firmware_version.py and displays the result as a badge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add dynamic sensor testing (NPM, BME280, Noise, Envea) to the self-test
based on enabled sensors in config. Results are included in the diagnostic report.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add new "Share Report" modal with readable textarea
- Add instructions to send logs to contact@aircarto.fr
- Add "Download (.txt)" button to save report as file
- Add "Select All" button for easy manual copy
- Remove complex clipboard API code that wasn't working
- Filename format: logs_nebuleair_{deviceId}_{date}.txt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add system info collection at start of test (device ID, name, RTC time, GPS)
- Display device info in logs header
- Fix clipboard copy with fallback for non-HTTPS contexts
- Use execCommand fallback for older browsers
- Use ASCII-safe characters for better compatibility
- Add error handling with manual copy fallback
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "Copy Report" button that generates a formatted diagnostic report:
- Device info (ID, modem version, timestamp)
- Test results summary with status icons
- Raw AT command responses for debugging
- Detailed execution logs
- Nicely formatted for sharing with manufacturer support
Enhanced logging with raw AT responses displayed in monospace format.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add informational network status check at the beginning of self-test:
- Shows connection mode (Hotspot, WiFi, or Ethernet)
- Displays SSID/connection name
- Shows IP address and hostname.local
- Add wifi_status endpoint in launcher.php using nmcli
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add two more tests to the modem self-test:
- Test 3: Signal Strength (AT+CSQ) with quality thresholds
- Test 4: Network Connection (AT+COPS?) with operator name lookup
Respects 1 second delay between each AT command.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "Run Self Test" button that opens a modal and runs diagnostic tests:
- Automatically enables modem_config_mode before tests
- Test 1: Modem connection (ATI command)
- Test 2: SIM card detection (AT+CCID? command)
- Respects delays between AT commands
- Always disables modem_config_mode after tests (even on failure)
- Shows real-time progress and detailed logs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add colored signal bars (1-5) based on signal power level.
Show signal quality description, RSSI in dBm, and quality index.
Color coding: red (poor) -> orange -> yellow -> green -> blue (excellent).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add operators.json with MCC/MNC codes for common operators.
Parse AT+COPS? response to show operator name, country, technology,
and connection mode in a user-friendly format.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add user-friendly alert for SIM card status with ICCID number.
Change all modem/SIM status messages to English.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace raw AT command output with Bootstrap alerts showing modem
connection status and model. Add collapsible section for raw logs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Retry up to 3 times if no valid frame is received
- Reduced wait time per attempt to 0.8s (total max ~3s with retries)
- Small delay between retries (0.2s)
- Only logs command on first attempt to reduce noise
This should eliminate the occasional 0 values caused by timing issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Some readings were returning 0 because the sensor hadn't fully
responded within 1 second. Increased to 1.5s for more reliable reads.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Increase wait time to 1 second for complete sensor response
- Read all available bytes from buffer instead of fixed 32
- Search for frame header (FF 02) anywhere in response data
(handles command echo or garbage before actual frame)
- Extract frame from header position for correct byte alignment
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The CAIRSENS sensor sends response in a single block, not two parts.
The initial read was consuming all 25 bytes leaving nothing for the
actual data read.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace readline() with read(32) to avoid truncation at 0x0A bytes
- Add reset_input_buffer() to clear stale data before each read
- Add initial read to consume echo/acknowledgment from sensor
- Add frame header validation (0xFF 0x02) to reject invalid data
- Add delays to allow sensor response time
Fixes issue where NO2/H2S sensors showed random spikes due to
binary data containing newline characters being misinterpreted.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements power saving optimizations to extend battery life on solar-powered remote air quality sensors:
- WiFi Power Saving: Disable WiFi 10 minutes after boot to save ~100-200mA
- Configurable via web UI checkbox in admin panel
- WiFi automatically re-enables after reboot for 10-minute configuration window
- Systemd timer (nebuleair-wifi-powersave.timer) manages automatic disable
- New wifi/power_save.py script checks database config and disables WiFi via nmcli
- HDMI Disable: Added hdmi_blanking=2 to boot config to save ~20-30mA
- Automatically configured during installation
- Database: Added wifi_power_saving boolean config (default: disabled)
- Uses INSERT OR IGNORE for safe updates to existing installations
- UI: Added checkbox control in admin.html for WiFi power saving
- Includes helpful description of power savings and behavior
- Services: Updated setup_services.sh and update_firmware.sh to manage new timer
Total power savings: ~120-230mA when WiFi power saving enabled
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed race condition issues where device name wasn't displaying properly:
Page title fixes:
- Added document.title update to sensors.html (was missing)
- wifi.html already had it but improved reliability
Sidebar device name fixes:
- Created updateSidebarDeviceName() function with retry logic
- Attempts update immediately, then at 100ms and 500ms delays
- Handles async sidebar loading timing issues
- Added console logging for debugging
- Both sensors.html and wifi.html now reliably show device name
This ensures the device ID/name always appears in:
1. Browser tab title (e.g., "NebuleAir_001")
2. Sidebar footer (bottom of navigation)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The light green background for the most recent data row wasn't displaying because Bootstrap's table striping was overriding it.
Changed CSS from targeting the row to targeting individual cells:
- .table .most-recent-row td
- .table-striped .most-recent-row td
Both with !important to override Bootstrap's table styles. Now the first row correctly displays with light green background.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Modified the sensors page to display a unified debug view for all Envea gas sensors:
Backend changes:
- Added new 'envea_debug' endpoint in launcher.php
- Calls: /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value_v2.py -d
- Returns raw debug output without parsing
Frontend changes:
- Replaced individual sensor cards with single combined card
- Card displays if any gas sensor is connected
- Shows list of connected sensors (NO2, H2S, NH3, etc.)
- New getENVEA_debug_values() function fetches debug data
- Raw output displayed in scrollable <pre> block
- No JSON parsing, no table formatting - just raw debug text
- Card width set to col-sm-6 for better visibility
This makes it easier to check if all sensors are working correctly by viewing the raw output.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>