272 lines
14 KiB
Markdown
272 lines
14 KiB
Markdown
# Tài liệu Kỹ thuật: Tự động hóa nạp FW (`core/auto_flash_worker.py`)
|
||
|
||
Module **Tự động hóa nạp FW** tự động quét mạng LAN, phát hiện thiết bị đích, và nạp firmware hàng loạt mà không cần thao tác thủ công. Được thiết kế cho môi trường sản xuất cần nạp FW nhanh cho nhiều thiết bị OpenWrt cùng lúc.
|
||
|
||
---
|
||
|
||
## 1. Kiến Trúc — Vai Trò File
|
||
|
||
| File | Vai trò |
|
||
| --------------------------- | ------------------------------------------------------------------------ |
|
||
| `core/auto_flash_worker.py` | `AutoFlashWorker` — QThread xử lý toàn bộ quy trình scan → flash tự động |
|
||
| `core/scanner.py` | `scan_network()` — quét mạng LAN (ping sweep + ARP table + Scapy) |
|
||
| `core/api_flash.py` | `flash_device_api()` — nạp FW qua LuCI HTTP API |
|
||
| `core/ssh_new_flash.py` | `flash_device_new_ssh()` — nạp FW qua SSH (paramiko/scp) |
|
||
| `main.py` | `AutoFlashWindow` — UI cửa sổ tự động hóa (PyQt6) |
|
||
| `ui/styles.py` | `AUTO_STYLE` — stylesheet riêng cho cửa sổ tự động hóa (tím) |
|
||
|
||
---
|
||
|
||
## 2. Sơ Đồ Luồng Tổng Quan
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[👤 Người dùng nhấn XÁC NHẬN & BẮT ĐẦU] --> B[AutoFlashWorker.run]
|
||
|
||
B --> P1["── Phase 1: Scan LAN ──"]
|
||
P1 --> S1["scan_network(network)"]
|
||
S1 --> F1{"Lọc bỏ:\n• Local IP\n• Gateway IP\n• 192.168.11.102"}
|
||
F1 --> C1{Đủ số lượng\nthiết bị?}
|
||
C1 -->|Có| P2["── Phase 2: Flash ──"]
|
||
C1 -->|Chưa đủ| C2{Đã scan\n≥ 20 lần?}
|
||
C2 -->|Chưa| W1["Chờ 5 giây\n→ scan lại"]
|
||
W1 --> S1
|
||
C2 -->|Rồi| T1["⚠️ scan_timeout\nThông báo lỗi"]
|
||
|
||
P2 --> D1["ThreadPoolExecutor\nNạp FW song song"]
|
||
D1 --> D2["_flash_one(device)"]
|
||
D2 --> D3{Kết quả?}
|
||
D3 -->|DONE| D4["✅ Thành công"]
|
||
D3 -->|FAIL| D5{Retry < 3?}
|
||
D5 -->|Có| D6["🔄 Chờ 2s → Retry"]
|
||
D6 --> D2
|
||
D5 -->|Không| D7["❌ Thất bại\nsau 3 lần"]
|
||
|
||
D4 --> D8["Tổng hợp kết quả"]
|
||
D7 --> D8
|
||
D8 --> D9["🏁 all_done(success, fail)"]
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Cấu Hình & Hằng Số
|
||
|
||
| Hằng số | Giá trị | Mô tả |
|
||
| ------------------- | ------- | ------------------------------------------------------ |
|
||
| `MAX_FLASH_RETRIES` | 3 | Số lần retry tối đa khi nạp FW thất bại cho 1 thiết bị |
|
||
| `MAX_SCAN_ROUNDS` | 20 | Số lần scan LAN tối đa trước khi báo timeout |
|
||
| Scan interval | 5 giây | Khoảng cách giữa các lần scan (check stop mỗi 0.5s) |
|
||
| Retry delay | 2 giây | Thời gian chờ trước khi retry nạp FW |
|
||
|
||
---
|
||
|
||
## 4. Tham Số Khởi Tạo Worker
|
||
|
||
```python
|
||
AutoFlashWorker(
|
||
network="192.168.11.0/24", # Dải mạng cần scan
|
||
target_count=5, # Số lượng thiết bị cần nạp
|
||
method="api", # "api" (LuCI) hoặc "ssh"
|
||
max_workers=10, # Số luồng nạp song song (0 = không giới hạn)
|
||
firmware_path="/path/fw.bin", # Đường dẫn file firmware
|
||
local_ip="192.168.11.50", # IP máy host (sẽ bị loại khỏi scan)
|
||
gateway_ip="192.168.11.1", # IP gateway (sẽ bị loại khỏi scan)
|
||
ssh_user="root", # SSH username (mặc định: root)
|
||
ssh_password="admin123a", # SSH password chính
|
||
ssh_backup_password="admin123a", # SSH password dự phòng
|
||
set_passwd=True, # Có đặt lại mật khẩu sau flash không
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Signal — Giao Tiếp Worker ↔ UI
|
||
|
||
| Signal | Kiểu dữ liệu | Khi nào emit |
|
||
| ---------------- | --------------- | --------------------------------------------------- |
|
||
| `log_message` | `str` | Mỗi dòng log (scan, flash, retry, kết quả) |
|
||
| `scan_found` | `int` | Sau mỗi lần scan — số thiết bị tìm thấy |
|
||
| `devices_ready` | `list[dict]` | Khi đủ thiết bị — danh sách `{ip, mac}` trước flash |
|
||
| `device_status` | `str, str` | Cập nhật trạng thái real-time: `(ip, message)` |
|
||
| `device_done` | `str, str, str` | Mỗi thiết bị xong: `(ip, mac, result)` |
|
||
| `flash_progress` | `int, int` | Tiến trình: `(done_count, total)` |
|
||
| `all_done` | `int, int` | Kết thúc: `(success_count, fail_count)` |
|
||
| `scan_timeout` | `int, int` | Scan hết lần: `(best_found, target_count)` |
|
||
| `stopped` | — | Khi worker dừng (bởi user hoặc timeout) |
|
||
|
||
---
|
||
|
||
## 6. Chi Tiết Quy Trình
|
||
|
||
### 6.1. Phase 1 — Scan Mạng LAN
|
||
|
||
```
|
||
Lần 1/20 → scan_network("192.168.11.0/24")
|
||
→ Lọc bỏ: local_ip, gateway_ip, 192.168.11.102
|
||
→ Tìm thấy 3/5 thiết bị → chưa đủ
|
||
→ Chờ 5 giây...
|
||
|
||
Lần 2/20 → scan_network(...)
|
||
→ Tìm thấy 5/5 thiết bị → ĐỦ!
|
||
→ Chuyển sang Phase 2
|
||
```
|
||
|
||
**Quy tắc lọc IP:**
|
||
|
||
- `local_ip` — IP của máy host (tránh nạp FW vào chính máy mình)
|
||
- `gateway_ip` — IP của router/gateway
|
||
- `192.168.11.102` — IP thiết bị đã cài FW sẵn, **chỉ được nạp ở chế độ Update FW**
|
||
|
||
**Timeout:**
|
||
|
||
- Sau **20 lần scan** mà chưa đủ thiết bị → emit `scan_timeout`
|
||
- UI hiện popup cảnh báo kèm gợi ý kiểm tra:
|
||
- Thiết bị đã bật và kết nối mạng chưa
|
||
- Dải mạng có đúng không
|
||
- Thử lại sau khi kiểm tra
|
||
|
||
### 6.2. Phase 2 — Nạp FW (có Auto-Retry)
|
||
|
||
Mỗi thiết bị được nạp trong `ThreadPoolExecutor` (chạy song song):
|
||
|
||
```
|
||
[192.168.11.103] Lần 1 → flash_device_api(...) → FAIL: Connection timeout
|
||
⚠️ Lần 1 thất bại
|
||
Chờ 2 giây...
|
||
[192.168.11.103] Lần 2 → flash_device_api(...) → FAIL: Upload error
|
||
⚠️ Lần 2 thất bại
|
||
Chờ 2 giây...
|
||
[192.168.11.103] Lần 3 → flash_device_api(...) → DONE
|
||
✅ Thành công (lần thứ 3)
|
||
```
|
||
|
||
**Quy trình retry:**
|
||
|
||
1. Thực hiện nạp FW (API hoặc SSH)
|
||
2. Nếu kết quả bắt đầu bằng `"DONE"` → thành công, dừng retry
|
||
3. Nếu thất bại và còn lần retry → log cảnh báo, chờ 2 giây, thử lại
|
||
4. Nếu thất bại sau 3 lần → log lỗi, báo kết quả `FAIL`
|
||
|
||
---
|
||
|
||
## 7. Giao Diện Cửa Sổ Tự Động (AutoFlashWindow)
|
||
|
||
### 7.1. Bố Cục
|
||
|
||
```
|
||
┌──────────────────────────────────────────┐
|
||
│ 🤖 Tự động hóa nạp FW │
|
||
├──────────────────────────────────────────┤
|
||
│ ⚙️ Cấu hình nạp (thu gọn được) │
|
||
│ FW: V3.0.6p5.bin │ Mạng: .11.0/24 │
|
||
│ Số lượng: 5 │ API (LuCI) │ Song song:10│
|
||
├──────────────────────────────────────────┤
|
||
│ [▶ XÁC NHẬN & BẮT ĐẦU] [■ DỪNG] │
|
||
│ 🔍 Đang scan: 3/5 thiết bị... ████░░ │
|
||
├──────────────────────────────────────────┤
|
||
│ 📋 Danh sách thiết bị │
|
||
│ ┌───┬──────────────┬────────────┬──────┐ │
|
||
│ │ # │ IP │ MAC │Kết quả│ │
|
||
│ ├───┼──────────────┼────────────┼──────┤ │
|
||
│ │ 1 │192.168.11.103│ AA:BB:CC.. │✅DONE│ │
|
||
│ │ 2 │192.168.11.104│ DD:EE:FF.. │⏳... │ │
|
||
│ │ 3 │192.168.11.105│ 11:22:33.. │🔄 R2 │ │
|
||
│ └───┴──────────────┴────────────┴──────┘ │
|
||
│ Tổng: 5 | Xong: 3 | ✅ 2 | ❌ 1 [📋Lịch sử]│
|
||
├──────────────────────────────────────────┤
|
||
│ 📝 Log (thu gọn được) │
|
||
│ 🚀 Bắt đầu chế độ tự động hóa nạp FW...│
|
||
│ 🔍 Scan lần 1/20... │
|
||
│ Tìm thấy 5/5 thiết bị │
|
||
│ ✅ Đủ 5 thiết bị! Bắt đầu nạp FW... │
|
||
│ ⚠️ [192.168.11.105] Lần 1 thất bại... │
|
||
│ 🔄 [192.168.11.105] Retry lần 2/3... │
|
||
└──────────────────────────────────────────┘
|
||
```
|
||
|
||
### 7.2. Các Thành Phần UI
|
||
|
||
| Thành phần | Mô tả |
|
||
| ------------------------- | ---------------------------------------------------------- |
|
||
| **Cấu hình nạp** | CollapsibleGroupBox — chọn FW, mạng, số lượng, phương thức |
|
||
| **Nút điều khiển** | XÁC NHẬN & BẮT ĐẦU / DỪNG — enable/disable theo trạng thái |
|
||
| **Trạng thái + Progress** | Hiển thị inline trạng thái scan/flash + progress bar |
|
||
| **Bảng thiết bị** | 4 cột: #, IP, MAC, Kết quả — cập nhật real-time |
|
||
| **Tổng hợp + Lịch sử** | Bộ đếm ✅/❌ + nút "📋 Lịch sử nạp" xem chi tiết |
|
||
| **Log** | CollapsibleGroupBox — log chi tiết toàn bộ quá trình |
|
||
|
||
---
|
||
|
||
## 8. Lịch Sử Nạp (Flash History)
|
||
|
||
Kết quả nạp được lưu ở **2 nơi** với cùng format:
|
||
|
||
| Nơi lưu | Phạm vi | Dữ liệu |
|
||
| ------------------------------- | ---------------------- | ------------------------------------ |
|
||
| `AutoFlashWindow._auto_history` | Phiên tự động hiện tại | `list[(ip, mac, result, timestamp)]` |
|
||
| `App.flashed_macs` | Toàn bộ session app | `dict{MAC: (ip, mac, result, ts)}` |
|
||
|
||
- Cả thành công ✅ lẫn thất bại ❌ đều được ghi lại
|
||
- Nút "📋 Lịch sử nạp" hiển thị danh sách với format: `[HH:MM:SS] ✅/❌ IP (MAC) — result`
|
||
- Lịch sử `_auto_history` reset mỗi khi nhấn "XÁC NHẬN & BẮT ĐẦU" lần mới
|
||
- Lịch sử `flashed_macs` tồn tại suốt phiên chạy app (cả manual và auto)
|
||
|
||
---
|
||
|
||
## 9. Quy Tắc Bảo Vệ IP `192.168.11.102`
|
||
|
||
| Chế độ | Được nạp 192.168.11.102? | Cơ chế |
|
||
| ------------------------ | :----------------------: | --------------------------------------- |
|
||
| **New Flash (thủ công)** | ❌ Không | Kiểm tra trước khi flash, hiện cảnh báo |
|
||
| **Update FW (thủ công)** | ✅ Có | Cho phép bình thường |
|
||
| **Tự động hóa** | ❌ Không | Lọc khỏi kết quả scan tự động |
|
||
|
||
---
|
||
|
||
## 10. Xử Lý Lỗi Tổng Hợp
|
||
|
||
| Tình huống | Hành vi |
|
||
| ------------------------------ | --------------------------------------------------- |
|
||
| Scan exception (network error) | Log lỗi, chờ 3s, scan lại (đếm vào MAX_SCAN_ROUNDS) |
|
||
| Scan 20 lần chưa đủ thiết bị | Emit `scan_timeout`, hiện popup cảnh báo, dừng |
|
||
| Flash thất bại lần 1-2 | Log cảnh báo, chờ 2s, retry tự động |
|
||
| Flash thất bại sau 3 lần retry | Log lỗi, đánh dấu ❌, tiếp tục device tiếp theo |
|
||
| User nhấn DỪNG | Set `_stop_flag`, dừng scan/flash, emit `stopped` |
|
||
| Chưa chọn firmware | Hiện popup cảnh báo, không cho bắt đầu |
|
||
| Mạng không hợp lệ | Hiện popup cảnh báo, không cho bắt đầu |
|
||
|
||
---
|
||
|
||
## 11. Hướng Dẫn Sử Dụng
|
||
|
||
### Bước 1: Mở tính năng
|
||
|
||
Nhấn nút **"🤖 Tự động hóa nạp FW"** ở cuối cửa sổ chính.
|
||
|
||
### Bước 2: Cấu hình
|
||
|
||
1. **Chọn firmware** — nhấn 📁 hoặc tự động lấy từ cửa sổ chính
|
||
2. **Dải mạng** — mặc định lấy từ IP máy host (ví dụ: `192.168.11.0/24`)
|
||
3. **Số lượng** — số thiết bị cần nạp (1–500)
|
||
4. **Phương thức** — API (LuCI) hoặc SSH
|
||
5. **Song song** — số thiết bị nạp cùng lúc (0 = tất cả cùng lúc)
|
||
|
||
### Bước 3: Bắt đầu
|
||
|
||
Nhấn **"▶ XÁC NHẬN & BẮT ĐẦU"** → xác nhận popup → hệ thống tự động:
|
||
|
||
1. Scan mạng liên tục cho đến khi đủ thiết bị (tối đa 20 lần)
|
||
2. Nạp FW song song cho tất cả thiết bị tìm được
|
||
3. Tự động retry nếu thiết bị nào bị lỗi (tối đa 3 lần)
|
||
4. Hiện thông báo tổng hợp khi hoàn thành
|
||
|
||
### Bước 4: Theo dõi
|
||
|
||
- **Bảng thiết bị** — trạng thái real-time từng thiết bị
|
||
- **Log** — chi tiết quá trình scan, flash, retry
|
||
- **Lịch sử nạp** — nhấn 📋 để xem danh sách đã nạp
|
||
|
||
### Dừng giữa chừng
|
||
|
||
Nhấn **"■ DỪNG"** — worker sẽ dừng an toàn sau khi hoàn thành device đang xử lý.
|