Files
nebuleair_pro_4g/update_firmware_from_file.sh
PaulVua 4e5e1a8144 v1.9.18: fix OTA - create_db.py manquant dans update scripts
Les MAJ OTA ne lancent pas create_db.py, donc toute nouvelle table
ajoutée par une release (ex: data_S88) reste inexistante en base.
Les timers tournent, le script s'exécute, mais l'INSERT échoue
silencieusement avec 'no such table' — capturé par le try/except,
exit 0, systemd voit success.

Symptôme observé sur les capteurs avec S88 activé: 'Get Data' marche
(live read), mais 'Mesures CO2 (Senseair S88)' montre 'Aucune donnée
disponible dans cette table'.

Fix: create_db.py est appelé en step 2 juste avant set_config.py
dans les deux scripts d'update (git pull et upload fichier).
Idempotent (CREATE IF NOT EXISTS + ALTER ADD COLUMN in try/except).

Self-bootstrap: après cette OTA, tous les capteurs auront toutes
les tables, y compris celles introduites dans des releases passées.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 17:03:07 +02:00

232 lines
7.3 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# NebuleAir Pro 4G - Update from uploaded ZIP file
# Usage: sudo ./update_firmware_from_file.sh /path/to/extracted/folder
echo "======================================"
echo "NebuleAir Pro 4G - Firmware Update (File Upload)"
echo "======================================"
echo "Started at: $(date)"
echo ""
# Set target directory
TARGET_DIR="/var/www/nebuleair_pro_4g"
EXCLUDE_FILE="$TARGET_DIR/.update-exclude"
# Function to print status messages
print_status() {
echo "[$(date '+%H:%M:%S')] $1"
}
# Function to check command success
check_status() {
if [ $? -eq 0 ]; then
print_status "$1 completed successfully"
else
print_status "$1 failed"
return 1
fi
}
# Validate arguments
if [ -z "$1" ]; then
print_status "✗ Error: No source directory provided"
print_status "Usage: $0 /path/to/extracted/folder"
exit 1
fi
SOURCE_DIR="$1"
if [ ! -d "$SOURCE_DIR" ]; then
print_status "✗ Error: Source directory does not exist: $SOURCE_DIR"
exit 1
fi
# Step 1: Validate source and compare versions
print_status "Step 1: Validating update package..."
if [ ! -f "$SOURCE_DIR/VERSION" ]; then
print_status "✗ Error: VERSION file not found in update package"
exit 1
fi
NEW_VERSION=$(cat "$SOURCE_DIR/VERSION" | tr -d '[:space:]')
OLD_VERSION="unknown"
if [ -f "$TARGET_DIR/VERSION" ]; then
OLD_VERSION=$(cat "$TARGET_DIR/VERSION" | tr -d '[:space:]')
fi
print_status "Current version: $OLD_VERSION"
print_status "New version: $NEW_VERSION"
# Step 2: Rsync with exclusions from .update-exclude
print_status ""
print_status "Step 2: Syncing files..."
# Build exclude args: use .update-exclude from the SOURCE (new version) if available,
# otherwise fall back to the one already installed
if [ -f "$SOURCE_DIR/.update-exclude" ]; then
EXCLUDE_FILE="$SOURCE_DIR/.update-exclude"
print_status "Using .update-exclude from update package"
elif [ -f "$TARGET_DIR/.update-exclude" ]; then
EXCLUDE_FILE="$TARGET_DIR/.update-exclude"
print_status "Using .update-exclude from current installation"
else
print_status "⚠ No .update-exclude file found, using built-in defaults"
# Fallback minimal exclusions
EXCLUDE_FILE=$(mktemp)
cat > "$EXCLUDE_FILE" <<'EXCL'
sqlite/sensors.db
sqlite/*.db-journal
sqlite/*.db-wal
logs/
.git/
config.json
deviceID.txt
wifi_list.csv
envea/data/
NPM/data/
*.lock
EXCL
fi
rsync -av --delete --exclude-from="$EXCLUDE_FILE" "$SOURCE_DIR/" "$TARGET_DIR/"
check_status "File sync (rsync)"
# Fix ownership and permissions
print_status "Fixing ownership..."
chown -R www-data:www-data "$TARGET_DIR/"
check_status "Ownership fix (chown)"
# Step 3: Update database (schema migration + config keys)
# create_db.py is idempotent; required to add tables introduced after the sensor
# was provisioned. Without it, OTA leaves new-sensor timers running but every
# write fails with "no such table".
print_status ""
print_status "Step 3: Updating database (schema migration + config keys)..."
/usr/bin/python3 "$TARGET_DIR/sqlite/create_db.py"
check_status "Database schema migration"
/usr/bin/python3 "$TARGET_DIR/sqlite/set_config.py"
check_status "Database configuration update"
# Step 4: Check and fix file permissions
print_status ""
print_status "Step 4: Checking file permissions..."
chmod +x "$TARGET_DIR/update_firmware.sh"
chmod +x "$TARGET_DIR/update_firmware_from_file.sh"
chmod 755 "$TARGET_DIR/sqlite/"*.py
chmod 755 "$TARGET_DIR/NPM/"*.py
chmod 755 "$TARGET_DIR/BME280/"*.py
chmod 755 "$TARGET_DIR/SARA/"*.py
chmod 755 "$TARGET_DIR/envea/"*.py
chmod 755 "$TARGET_DIR/MPPT/"*.py 2>/dev/null
chmod 755 "$TARGET_DIR/wifi/"*.py 2>/dev/null
check_status "File permissions update"
# Step 4b: Ensure Apache/PHP config allows file uploads (.htaccess + php.ini)
APACHE_MAIN_CONF="/etc/apache2/apache2.conf"
if grep -q '<Directory /var/www/>' "$APACHE_MAIN_CONF"; then
if ! sed -n '/<Directory \/var\/www\/>/,/<\/Directory>/p' "$APACHE_MAIN_CONF" | grep -q "AllowOverride All"; then
sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' "$APACHE_MAIN_CONF"
print_status "✓ AllowOverride All enabled for Apache"
APACHE_CHANGED=true
fi
fi
PHP_INI=$(php -r "echo php_ini_loaded_file();" 2>/dev/null)
if [ -n "$PHP_INI" ]; then
CURRENT_UPLOAD=$(grep -oP 'upload_max_filesize = \K\d+' "$PHP_INI" 2>/dev/null)
if [ -n "$CURRENT_UPLOAD" ] && [ "$CURRENT_UPLOAD" -lt 50 ]; then
sed -i 's/upload_max_filesize = .*/upload_max_filesize = 50M/' "$PHP_INI"
sed -i 's/post_max_size = .*/post_max_size = 55M/' "$PHP_INI"
print_status "✓ PHP upload limits set to 50M"
APACHE_CHANGED=true
fi
fi
if [ "${APACHE_CHANGED:-false}" = true ]; then
systemctl reload apache2 2>/dev/null
print_status "✓ Apache reloaded"
fi
# Step 4c: Reconcile systemd services with the repo (self-heal)
# Same logic as update_firmware.sh: re-run setup_services.sh so any missing,
# masked, or newly-added service in the canonical setup script is installed.
# git config core.fileMode=false strips +x, so chmod first.
print_status ""
print_status "Step 4c: Reconciling systemd services with setup_services.sh..."
SETUP_SERVICES="$TARGET_DIR/services/setup_services.sh"
if [ -f "$SETUP_SERVICES" ]; then
chmod +x "$SETUP_SERVICES"
"$SETUP_SERVICES"
check_status "Setup services reconciliation"
else
print_status "⚠ setup_services.sh not found, skipping"
fi
# Step 5: Restart critical services
print_status ""
print_status "Step 5: Managing system services..."
services=(
"nebuleair-npm-data.timer"
"nebuleair-envea-data.timer"
"nebuleair-sara-data.timer"
"nebuleair-bme280-data.timer"
"nebuleair-mppt-data.timer"
"nebuleair-noise-data.timer"
"nebuleair-wifi-powersave.timer"
)
for service in "${services[@]}"; do
if systemctl list-unit-files | grep -q "$service"; then
if systemctl is-enabled --quiet "$service" 2>/dev/null; then
print_status "Restarting enabled service: $service"
systemctl restart "$service"
if systemctl is-active --quiet "$service"; then
print_status "$service is running"
else
print_status "$service failed to start"
fi
else
print_status " Service $service is disabled, skipping restart"
fi
else
print_status " Service $service not found (may not be installed)"
fi
done
# Step 6: System health check
print_status ""
print_status "Step 6: System health check..."
disk_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$disk_usage" -gt 90 ]; then
print_status "⚠ Warning: Disk usage is high ($disk_usage%)"
else
print_status "✓ Disk usage is acceptable ($disk_usage%)"
fi
if [ -f "$TARGET_DIR/sqlite/sensors.db" ]; then
print_status "✓ Database file exists"
else
print_status "⚠ Warning: Database file not found"
fi
# Cleanup logs > 10MB
find "$TARGET_DIR/logs" -name "*.log" -size +10M -exec truncate -s 0 {} \;
check_status "Log cleanup"
# Step 7: Cleanup temporary files
print_status ""
print_status "Step 7: Cleaning up temporary files..."
rm -rf /tmp/nebuleair_update/
check_status "Temp cleanup"
print_status ""
print_status "======================================"
print_status "Update from $OLD_VERSION to $NEW_VERSION completed successfully!"
print_status "======================================"
exit 0