5.5 KiB
5.5 KiB
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
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.