fix(cli): lazy settings fetch and full device erase
Download settings only for --show or when applying edits; skip upload when unchanged; erase entire device root including settings.json. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
155
cli.py
155
cli.py
@@ -2,8 +2,10 @@
|
||||
"""
|
||||
LED Bar Configuration CLI Tool
|
||||
|
||||
Command-line interface for downloading, editing, and uploading settings.json
|
||||
to/from MicroPython devices via mpremote.
|
||||
Command-line interface for editing settings.json on MicroPython devices via mpremote.
|
||||
Settings are downloaded from the device only when displaying (--show) or when applying
|
||||
setting changes; uploads occur only when something changed. Use --erase to clear the
|
||||
device filesystem (including settings).
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -279,10 +281,13 @@ def main() -> None:
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
# Download and print current settings
|
||||
# Show help (no device I/O)
|
||||
%(prog)s
|
||||
|
||||
# Download, edit device name and brightness, then upload
|
||||
# Show current settings.json from device (read-only)
|
||||
%(prog)s --show
|
||||
|
||||
# Edit device name and brightness, then upload only if values changed
|
||||
%(prog)s -n "LED-Strip-1" -b 128
|
||||
|
||||
# Set multiple parameters
|
||||
@@ -500,7 +505,7 @@ Examples:
|
||||
"-e", "--erase",
|
||||
dest="erase_all",
|
||||
action="store_true",
|
||||
help="Erase all code on the device (delete all files except settings.json)"
|
||||
help="Erase the device filesystem: delete all files and directories at device root (including settings.json and presets.json)",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -516,6 +521,9 @@ Examples:
|
||||
)
|
||||
|
||||
try:
|
||||
if len(sys.argv) <= 1:
|
||||
parser.print_help()
|
||||
return
|
||||
args = parser.parse_args()
|
||||
ordered_actions = _get_ordered_actions(sys.argv)
|
||||
except ValueError as e:
|
||||
@@ -631,14 +639,12 @@ Examples:
|
||||
|
||||
elif action_name == 'erase_all':
|
||||
try:
|
||||
print(f"Erasing all code on device {port}...", file=sys.stderr)
|
||||
print(f"Erasing device filesystem on {port}...", file=sys.stderr)
|
||||
conn = DeviceConnection(port)
|
||||
items = conn.list_files('')
|
||||
for name, is_dir, size in items:
|
||||
if name == "settings.json":
|
||||
continue
|
||||
conn.delete(name)
|
||||
print("Erase complete.", file=sys.stderr)
|
||||
print("Erase complete (device root is empty).", file=sys.stderr)
|
||||
except Exception as e:
|
||||
print(f"Error erasing device: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
@@ -735,40 +741,86 @@ Examples:
|
||||
# Clamp into single-byte range; store as int in settings.json
|
||||
edits["id"] = max(0, min(255, args.device_id))
|
||||
|
||||
# 1. Download: get current settings from device
|
||||
try:
|
||||
print(f"Downloading settings from {args.port}...", file=sys.stderr)
|
||||
settings = download_settings(args.port)
|
||||
print("Settings downloaded successfully.", file=sys.stderr)
|
||||
except Exception as e:
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower():
|
||||
print(f"Error: Connection timeout. Check device connection on {args.port}", file=sys.stderr)
|
||||
else:
|
||||
print(f"Error downloading settings: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
settings_work = args.show or bool(edits)
|
||||
|
||||
if settings_work:
|
||||
try:
|
||||
print(f"Downloading settings from {args.port}...", file=sys.stderr)
|
||||
settings = download_settings(args.port)
|
||||
print("Settings downloaded successfully.", file=sys.stderr)
|
||||
except Exception as e:
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower():
|
||||
print(
|
||||
f"Error: Connection timeout. Check device connection on {args.port}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(f"Error downloading settings: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if args.show:
|
||||
print_settings(settings)
|
||||
if not edits and args.preset is None:
|
||||
return
|
||||
|
||||
changed_edits: Dict[str, Any] = {}
|
||||
for key, value in edits.items():
|
||||
if settings.get(key) != value:
|
||||
changed_edits[key] = value
|
||||
|
||||
if edits and not changed_edits:
|
||||
print("No settings changes detected; skipping settings upload.", file=sys.stderr)
|
||||
|
||||
if changed_edits:
|
||||
print(f"Applying {len(changed_edits)} setting change(s)...", file=sys.stderr)
|
||||
settings.update(changed_edits)
|
||||
|
||||
# If --show only, print and exit (unless presets or settings are being written)
|
||||
if args.show:
|
||||
print_settings(settings)
|
||||
if not edits and args.preset is None:
|
||||
return
|
||||
|
||||
# 2. Edit: only apply/upload settings when values actually change
|
||||
changed_edits: Dict[str, Any] = {}
|
||||
for key, value in edits.items():
|
||||
if settings.get(key) != value:
|
||||
changed_edits[key] = value
|
||||
if args.preset is not None:
|
||||
pattern = args.pattern if args.pattern is not None else "on"
|
||||
try:
|
||||
print(f"Downloading presets from {args.port}...", file=sys.stderr)
|
||||
presets_data = download_presets(args.port)
|
||||
entry = presets_data.get(args.preset)
|
||||
if not isinstance(entry, dict):
|
||||
entry = {}
|
||||
entry["p"] = pattern
|
||||
presets_data[args.preset] = entry
|
||||
print(
|
||||
f"Writing preset {args.preset!r} (pattern={pattern}) to {PRESETS_REMOTE}...",
|
||||
file=sys.stderr,
|
||||
)
|
||||
upload_presets(args.port, presets_data, reset=not bool(edits))
|
||||
print("Presets uploaded successfully.", file=sys.stderr)
|
||||
if not edits:
|
||||
print("Device will reset.", file=sys.stderr)
|
||||
except Exception as e:
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower():
|
||||
print(
|
||||
f"Error: Connection timeout. Check device connection on {args.port}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(f"Error uploading presets: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if edits and not changed_edits:
|
||||
print("No settings changes detected; skipping settings upload.", file=sys.stderr)
|
||||
if changed_edits:
|
||||
try:
|
||||
print(f"\nUploading settings to {args.port}...", file=sys.stderr)
|
||||
upload_settings(args.port, settings)
|
||||
print("Settings uploaded successfully. Device will reset.", file=sys.stderr)
|
||||
except Exception as e:
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower():
|
||||
print(
|
||||
f"Error: Connection timeout. Check device connection on {args.port}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(f"Error uploading settings: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
if changed_edits:
|
||||
print(f"Applying {len(changed_edits)} setting change(s)...", file=sys.stderr)
|
||||
settings.update(changed_edits)
|
||||
|
||||
print_settings(settings)
|
||||
|
||||
# 3a. Presets file (led-driver presets.json)
|
||||
if args.preset is not None:
|
||||
pattern = args.pattern if args.pattern is not None else "on"
|
||||
try:
|
||||
@@ -783,29 +835,24 @@ Examples:
|
||||
f"Writing preset {args.preset!r} (pattern={pattern}) to {PRESETS_REMOTE}...",
|
||||
file=sys.stderr,
|
||||
)
|
||||
upload_presets(args.port, presets_data, reset=not bool(edits))
|
||||
upload_presets(args.port, presets_data, reset=True)
|
||||
print("Presets uploaded successfully.", file=sys.stderr)
|
||||
if not edits:
|
||||
print("Device will reset.", file=sys.stderr)
|
||||
print("Device will reset.", file=sys.stderr)
|
||||
except Exception as e:
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower():
|
||||
print(f"Error: Connection timeout. Check device connection on {args.port}", file=sys.stderr)
|
||||
print(
|
||||
f"Error: Connection timeout. Check device connection on {args.port}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(f"Error uploading presets: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
# 3b. Settings upload (resets device)
|
||||
if changed_edits:
|
||||
try:
|
||||
print(f"\nUploading settings to {args.port}...", file=sys.stderr)
|
||||
upload_settings(args.port, settings)
|
||||
print("Settings uploaded successfully. Device will reset.", file=sys.stderr)
|
||||
except Exception as e:
|
||||
if "timeout" in str(e).lower() or "connection" in str(e).lower():
|
||||
print(f"Error: Connection timeout. Check device connection on {args.port}", file=sys.stderr)
|
||||
else:
|
||||
print(f"Error uploading settings: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if ordered_actions:
|
||||
return
|
||||
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user