ESP32/flash_and_config.py

199 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Flash uniform firmware to all ESP32 devices, then reconfigure via serial
This is much faster than building unique firmwares for each device
"""
import os
import sys
import subprocess
import argparse
import glob
from pathlib import Path
import time
def detect_devices():
"""Detect all ESP32 devices"""
devices = sorted(glob.glob('/dev/ttyUSB*'))
return devices
def build_firmware(project_dir):
"""Build the firmware once"""
print("=" * 60)
print("Building firmware (one time)...")
print("=" * 60)
result = subprocess.run(
['idf.py', 'build'],
cwd=project_dir,
capture_output=False
)
if result.returncode != 0:
print("✗ Build failed!")
return False
print("✓ Build complete")
return True
def flash_device(port, project_dir):
"""Flash a single device"""
try:
result = subprocess.run(
['idf.py', '-p', port, 'flash'],
cwd=project_dir,
capture_output=True,
text=True,
timeout=120
)
return result.returncode == 0
except Exception as e:
return False
def flash_all_devices(devices, project_dir):
"""Flash all devices with the same firmware"""
print(f"\nFlashing {len(devices)} devices...")
success_count = 0
for idx, dev in enumerate(devices, 1):
print(f"[{idx:2d}/{len(devices)}] Flashing {dev}...", end='', flush=True)
if flash_device(dev, project_dir):
print("")
success_count += 1
else:
print("")
print(f"\nFlashed: {success_count}/{len(devices)}")
return success_count
def reconfigure_devices(ssid, password, start_ip, gateway="192.168.1.1"):
"""Reconfigure devices using the reconfig script"""
script_path = os.path.join(os.path.dirname(__file__), 'reconfig_simple.py')
if not os.path.exists(script_path):
print(f"Error: {script_path} not found!")
return False
print("\n" + "=" * 60)
print("Reconfiguring WiFi settings via serial...")
print("=" * 60)
cmd = [
'python3', script_path,
'-s', ssid,
'-p', password,
'--start-ip', start_ip,
'-g', gateway
]
result = subprocess.run(cmd)
return result.returncode == 0
def main():
parser = argparse.ArgumentParser(
description='Flash and configure all ESP32 devices',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
This script:
1. Builds firmware ONCE
2. Flashes the SAME firmware to all devices (fast!)
3. Reconfigures each device via serial with unique IP
Much faster than building 32 different firmwares!
Examples:
# Basic usage
%(prog)s --ssid MyWiFi --password mypass
# Custom IP range
%(prog)s --ssid MyWiFi --password mypass --start-ip 192.168.1.100
# Build only (no flash)
%(prog)s --build-only
# Reconfigure only (no flash)
%(prog)s --reconfig-only --ssid MyWiFi --password mypass
"""
)
parser.add_argument('--ssid', help='WiFi SSID')
parser.add_argument('--password', help='WiFi password')
parser.add_argument('--start-ip', default='192.168.1.50',
help='Starting IP address (default: 192.168.1.50)')
parser.add_argument('--gateway', default='192.168.1.1',
help='Gateway IP (default: 192.168.1.1)')
parser.add_argument('--project-dir', default=None,
help='ESP32 project directory (default: current dir)')
parser.add_argument('--build-only', action='store_true',
help='Only build, do not flash')
parser.add_argument('--reconfig-only', action='store_true',
help='Only reconfigure, do not build/flash')
parser.add_argument('--skip-build', action='store_true',
help='Skip build, use existing firmware')
args = parser.parse_args()
# Determine project directory
if args.project_dir:
project_dir = args.project_dir
else:
project_dir = os.path.dirname(os.path.abspath(__file__))
if not os.path.exists(os.path.join(project_dir, 'CMakeLists.txt')):
print(f"Error: Not an ESP-IDF project directory: {project_dir}")
return 1
# Detect devices
devices = detect_devices()
if not devices and not args.build_only:
print("Error: No devices found!")
return 1
print(f"Found {len(devices)} device(s)")
# Reconfigure only mode
if args.reconfig_only:
if not args.ssid or not args.password:
print("Error: --ssid and --password required for reconfigure mode")
return 1
return 0 if reconfigure_devices(args.ssid, args.password, args.start_ip, args.gateway) else 1
# Build firmware
if not args.skip_build:
if not build_firmware(project_dir):
return 1
if args.build_only:
print("\n Build complete. Use --skip-build to flash later.")
return 0
# Flash all devices
flash_count = flash_all_devices(devices, project_dir)
if flash_count == 0:
print("✗ No devices flashed successfully")
return 1
# Reconfigure if credentials provided
if args.ssid and args.password:
print("\nWaiting for devices to boot...")
time.sleep(5)
if not reconfigure_devices(args.ssid, args.password, args.start_ip, args.gateway):
print("✗ Reconfiguration failed")
return 1
else:
print("\n" + "=" * 60)
print("Flashing complete!")
print("=" * 60)
print("\nTo configure WiFi settings, run:")
print(f" python3 reconfig_simple.py -s YourSSID -p YourPassword --start-ip {args.start_ip}")
print("\n✓ Done!")
return 0
if __name__ == '__main__':
sys.exit(main())