# Tài liệu Kỹ thuật: Flash Firmware qua LuCI API (`core/api_flash.py`) Module `api_flash.py` tự động hoá quá trình nạp firmware cho thiết bị **OpenWrt** thông qua giao diện web **LuCI HTTP**. Được dùng trong chế độ **Nạp Mới FW** với method `"api"`. --- ## 1. Kiến Trúc — Vai Trò File | File | Vai trò | | -------------------------- | ----------------------------------------------------------------------- | | `core/api_flash.py` | Logic flash 3 bước (login → upload → proceed) qua LuCI | | `core/flash_new_worker.py` | `NewFlashThread` — dispatch tới `flash_device_api()` khi `method="api"` | | `main.py` | UI PyQt6, chọn mode/method, truyền tham số vào worker | --- ## 2. Sơ Đồ Luồng ```mermaid flowchart TD A[NewFlashThread - method=api] --> B[flash_device_api] B --> S1["STEP 1: Login\nGET /cgi-bin/luci — phát hiện field name\nPOST username=root & password="] S1 --> C1{Thành công?} C1 -->|sysauth cookie + stok| S2 C1 -->|HTTP 403| F1["FAIL: Login denied (403)"] C1 -->|Không có session| F2["FAIL: Login failed — no session"] S2["STEP 2: Upload Firmware\nPOST /flashops\nmultipart: image=firmware.bin"] --> C2{Response?} C2 -->|Trang Verify + Proceed| S3 C2 -->|HTTP ≠ 200| F3["FAIL: Upload HTTP xxx"] C2 -->|invalid image| F4["FAIL: Invalid firmware image"] C2 -->|unsupported| F5["FAIL: Firmware not compatible"] C2 -->|Vẫn hiện form upload| F6["FAIL: Upload ignored by server"] S3["STEP 3: Proceed\nPOST step=2 & keep=empty"] --> C3{Response?} C3 -->|Connection dropped / Timeout| R["DONE ✅ — Device đang reboot"] C3 -->|200 OK| R ``` --- ## 3. Chi Tiết Kỹ Thuật HTTP ### Step 1 — Login ``` GET http://{IP}/cgi-bin/luci → Lấy HTML login, phát hiện field name POST http://{IP}/cgi-bin/luci → Đăng nhập ``` **Tự động phát hiện field name tương thích:** | Phiên bản | Field | | --------------------- | --------------------------------- | | Barrier Breaker 14.07 | `username` / `password` | | OpenWrt mới hơn | `luci_username` / `luci_password` | **Lấy session:** `stok` token được tìm tuần tự trong URL → body HTML → redirect history. Cookie `sysauth` là fallback nếu không có `stok`. ### Step 2 — Upload Firmware ``` POST http://{IP}/cgi-bin/luci/;stok={TOKEN}/admin/system/flashops Content-Type: multipart/form-data image = firmware.bin (file upload) keep = (không gửi) → bỏ tích "Keep Settings" = Clean Flash ``` Thành công khi response trả về trang **"Flash Firmware - Verify"** chứa từ khoá `verify` + `proceed`. ### Step 3 — Confirm (Proceed) ``` POST http://{IP}/cgi-bin/luci/;stok={TOKEN}/admin/system/flashops step = 2 keep = (empty) ``` **Đứt kết nối = Thành công:** Device bắt đầu flash → SSH/HTTP request bị drop là hành vi mong muốn. `ConnectionError` và `ReadTimeout` đều được bắt và trả về `"DONE"`. --- ## 4. Bảng Status UI | Icon | Status | Điều kiện | | ---- | ---------------------------------------- | ------------------------------------------ | | ⏳ | `Logging in...` | Đang POST login vào LuCI | | ⏳ | `Uploading firmware...` | Đang upload file .bin | | ⏳ | `Confirming (Proceed)...` | Đang gửi lệnh xác nhận flash | | ⏳ | `Rebooting...` | Chờ device khởi động lại | | ✅ | `DONE` | Flash thành công | | ✅ | `DONE (rebooting)` | Flash thành công, timeout khi chờ response | | ❌ | `FAIL: Cannot connect` | Không kết nối được (sai IP / khác mạng) | | ❌ | `FAIL: Login denied (403)` | Sai mật khẩu LuCI | | ❌ | `FAIL: Login failed — no session` | Không có cookie/token sau login | | ❌ | `FAIL: Upload HTTP xxx` | Server trả lỗi HTTP khi upload | | ❌ | `FAIL: Invalid firmware image` | File firmware không hợp lệ | | ❌ | `FAIL: Firmware not compatible` | Firmware không tương thích thiết bị | | ❌ | `FAIL: Upload ignored by server` | Server không xử lý file (sai form field) | | ❌ | `FAIL: Unexpected response after upload` | Không nhận được trang Verify | --- ## 5. Xử Lý Song Song ``` NewFlashThread (QThread) └── ThreadPoolExecutor (max_workers = N) ├── Thread 1 → flash_device_api(IP_1) ├── Thread 2 → flash_device_api(IP_2) └── Thread N → flash_device_api(IP_N) ``` | Concurrent devices | Ý nghĩa | | ------------------ | --------------------------------- | | `10` (mặc định) | Flash 10 thiết bị song song | | `0` | Unlimited — flash tất cả cùng lúc | | `1` | Tuần tự — từng thiết bị một | Mỗi thiết bị có `requests.Session()` riêng — không bị lẫn cookie/token.