feat: Add v0.3 OTA updates — dual partition, esp-ota tool, rollback
Dual OTA partition table (ota_0/ota_1, 1920 KB each) on 4MB flash. Firmware gains OTA command, LED_OTA double-blink, version in STATUS, and automatic rollback validation. Pi-side esp-ota tool serves firmware via HTTP and orchestrates the update flow. esp-fleet gains ota subcommand.
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
"""Query all ESP32 CSI sensors in parallel."""
|
||||
|
||||
import concurrent.futures
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
DEFAULT_PORT = 5501
|
||||
@@ -14,6 +16,8 @@ SENSORS = [
|
||||
("hollow-acorn", "hollow-acorn.local"),
|
||||
]
|
||||
|
||||
ESP_OTA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "esp-ota")
|
||||
|
||||
USAGE = """\
|
||||
Usage: esp-fleet <command> [args...]
|
||||
|
||||
@@ -25,11 +29,14 @@ Commands:
|
||||
rate <10-100> Set ping rate on all devices
|
||||
power <2-20> Set TX power on all devices
|
||||
reboot Reboot all devices
|
||||
ota [firmware.bin] OTA update all devices (sequentially)
|
||||
|
||||
Examples:
|
||||
esp-fleet status
|
||||
esp-fleet identify
|
||||
esp-fleet rate 50"""
|
||||
esp-fleet rate 50
|
||||
esp-fleet ota
|
||||
esp-fleet ota /path/to/firmware.bin"""
|
||||
|
||||
|
||||
def query(name, host, cmd):
|
||||
@@ -54,11 +61,33 @@ def query(name, host, cmd):
|
||||
sock.close()
|
||||
|
||||
|
||||
def run_ota(firmware=None):
|
||||
"""Run OTA on each sensor sequentially."""
|
||||
for name, host in SENSORS:
|
||||
print(f"\n{'='*40}")
|
||||
print(f"OTA: {name} ({host})")
|
||||
print(f"{'='*40}")
|
||||
cmd = [ESP_OTA, host]
|
||||
if firmware:
|
||||
cmd += ["-f", firmware]
|
||||
result = subprocess.run(cmd)
|
||||
if result.returncode != 0:
|
||||
print(f"ERR: OTA failed for {name}, stopping fleet OTA", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print(f"\nAll {len(SENSORS)} devices updated.")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
|
||||
print(USAGE)
|
||||
sys.exit(0 if sys.argv[1:] and sys.argv[1] in ("-h", "--help") else 2)
|
||||
|
||||
# Handle OTA subcommand separately (sequential, not parallel)
|
||||
if sys.argv[1].lower() == "ota":
|
||||
firmware = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
run_ota(firmware)
|
||||
return
|
||||
|
||||
cmd = " ".join(sys.argv[1:]).strip().upper()
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=len(SENSORS)) as pool:
|
||||
|
||||
Reference in New Issue
Block a user