initial aubox skeleton: web-UI, kirin DLOAD, firmware library
- FastAPI Web-UI auf 127.0.0.1:8080 mit Geräte-Live-Erkennung, sandboxed File-Browser, Firmware-Library (SQLite + Auto-Identifikation) - Huawei update.app Parser: extrahiert Hardware-ID, Section-Layout, BOOT/SYSTEM-Vorhandensein direkt aus den Headern - Kirin Download-Mode: hisi-idt-Protokoll-Implementation gegen pyusb - USB-Erkennung für Huawei (DLOAD/Fastboot-D), Google, MediaTek, Qualcomm EDL - Huawei-P10-Lite-Workflow (eRecovery + Testpoint-DLOAD-Pfade) - Docker-Compose mit USB-Passthrough (Major 189) für Re-Enumeration - udev-Regeln + Setup-Script für Debian/Ubuntu/Pi-OS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
"""CLI-Einstiegspunkt: `python -m aubox <command>`."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
from . import p10lite, usb
|
||||
from .kirin import KirinDload
|
||||
|
||||
|
||||
def cmd_detect(_args: argparse.Namespace) -> int:
|
||||
devs = usb.scan()
|
||||
if not devs:
|
||||
print("Kein bekanntes Hersteller-Gerät angeschlossen.")
|
||||
print("Probiere `lsusb` für die rohe Liste.")
|
||||
return 1
|
||||
for d in devs:
|
||||
print(d)
|
||||
if d.mode.notes:
|
||||
print(f" {d.mode.notes}")
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_p10lite_frp(args: argparse.Namespace) -> int:
|
||||
if args.method == "erecovery":
|
||||
print(p10lite.erecovery_instructions())
|
||||
return 0
|
||||
|
||||
if args.method == "dload-erase":
|
||||
try:
|
||||
plan = p10lite.dload_erase_plan()
|
||||
except FileNotFoundError as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
return 2
|
||||
|
||||
print("Plan:")
|
||||
for stage in plan["stages"]:
|
||||
print(f" - {stage['label']}: {stage['file']} -> 0x{stage['addr']:08x}")
|
||||
print()
|
||||
print("Bitte jetzt Testpoint setzen und USB anschließen.")
|
||||
print("Warte auf Kirin DLOAD (12d1:1100)...")
|
||||
|
||||
for _ in range(60):
|
||||
if usb.find_first("kirin-dload") is not None:
|
||||
break
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
print("Timeout: kein Kirin DLOAD erschienen.", file=sys.stderr)
|
||||
return 3
|
||||
|
||||
print("Gerät erkannt. Sende Loader-Stages...")
|
||||
with KirinDload() as k:
|
||||
for stage in plan["stages"]:
|
||||
print(f" -> {stage['label']}")
|
||||
k.send_loader(stage["file"], stage["addr"])
|
||||
# Zwischen den Stages re-enumeriert das Gerät evtl.
|
||||
time.sleep(2)
|
||||
|
||||
print("Loader-Stages gesendet. Erwarteter Folgemodus:",
|
||||
plan["post"])
|
||||
print("Nächster Schritt (manuell, bis Workflow ausgereift):")
|
||||
print(" fastboot devices")
|
||||
print(f" fastboot erase {plan['frp_partition']}")
|
||||
return 0
|
||||
|
||||
print(f"Methode {args.method!r} noch nicht implementiert.", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
|
||||
def cmd_web(args: argparse.Namespace) -> int:
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"aubox.web.app:app",
|
||||
host=args.host,
|
||||
port=args.port,
|
||||
reload=args.reload,
|
||||
log_level="info",
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
p = argparse.ArgumentParser(prog="aubox")
|
||||
sub = p.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
sp_detect = sub.add_parser("detect", help="Angeschlossene Geräte erkennen")
|
||||
sp_detect.set_defaults(func=cmd_detect)
|
||||
|
||||
sp_web = sub.add_parser("web", help="Lokale Web-UI starten")
|
||||
sp_web.add_argument("--host", default="127.0.0.1",
|
||||
help="Bind-Adresse (Default: 127.0.0.1, im Container 0.0.0.0)")
|
||||
sp_web.add_argument("--port", type=int, default=8080)
|
||||
sp_web.add_argument("--reload", action="store_true",
|
||||
help="Auto-Reload bei Code-Änderungen (Entwicklung)")
|
||||
sp_web.set_defaults(func=cmd_web)
|
||||
|
||||
sp_p10 = sub.add_parser("p10lite", help="Workflows für Huawei P10 Lite")
|
||||
p10_sub = sp_p10.add_subparsers(dest="p10_cmd", required=True)
|
||||
|
||||
sp_frp = p10_sub.add_parser("frp-remove", help="Google-Account-Sperre entfernen")
|
||||
sp_frp.add_argument(
|
||||
"--method",
|
||||
choices=["erecovery", "dload-erase", "dload-flash"],
|
||||
default="erecovery",
|
||||
help="Welcher Pfad? Default: erecovery (sicherster, kein Loader nötig)",
|
||||
)
|
||||
sp_frp.set_defaults(func=cmd_p10lite_frp)
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = build_parser().parse_args(argv)
|
||||
return args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user