update UI, version

This commit is contained in:
2026-03-09 19:33:00 +07:00
parent 19febeaf3f
commit 042c50536c
4 changed files with 501 additions and 321 deletions

150
README.md
View File

@@ -1,9 +1,10 @@
# ⚡ Mira Firmware Loader
Công cụ desktop dùng để **scan, phát hiện và flash firmware hàng loạt** cho các thiết bị OpenWrt trong mạng LAN.
Công cụ desktop dùng để **scan, phát hiện và flash firmware hàng loạt** cho các thiết bị OpenWrt trong mạng LAN.
Hỗ trợ nạp **thủ công** (chọn thiết bị → flash) và **tự động hóa** (scan → phát hiện → flash → retry).
> **Tech stack:** Python 3.9+ · PyQt6 · Paramiko/SCP · Scapy · Requests · PyInstaller
> **Phiên bản:** `1.1.3`
> **Phiên bản:** `1.2.0`
---
@@ -11,7 +12,7 @@ Công cụ desktop dùng để **scan, phát hiện và flash firmware hàng lo
```text
Mira_Firmware_Loader/
├── main.py # UI chính (PyQt6)
├── main.py # UI chính (PyQt6) — App + AutoFlashWindow
├── version.txt # Số phiên bản ứng dụng
├── requirements.txt # Danh sách dependencies
├── core/
@@ -22,17 +23,19 @@ Mira_Firmware_Loader/
│ ├── ssh_new_flash.py # Luồng SSH cho chế độ Nạp Mới (Telnet → set passwd → SSH)
│ ├── ssh_update_flash.py # Luồng SSH cho chế độ Update (SSH trực tiếp)
│ ├── flash_new_worker.py # NewFlashThread — QThread điều phối Nạp Mới FW
── flash_update_worker.py # UpdateFlashThread — QThread điều phối Update FW
── flash_update_worker.py # UpdateFlashThread — QThread điều phối Update FW
│ └── auto_flash_worker.py # AutoFlashWorker — QThread tự động scan → flash → retry
├── ui/
│ ├── components.py # Custom Qt Widgets (CollapsibleGroupBox)
│ └── styles.py # Stylesheet toàn ứng dụng
│ └── styles.py # Stylesheet toàn ứng dụng (STYLE + AUTO_STYLE)
├── utils/
│ ├── network.py # Helper IP / network (get_local_ip, get_default_network)
│ └── system.py # Lấy thông tin máy, resource path cho PyInstaller
├── docs/
│ ├── api_flash_docs.md # Tài liệu kỹ thuật LuCI API flash
│ ├── load_fw_ssh_docs.md # Tài liệu kỹ thuật SSH flash (cả 2 luồng)
── scanner_docs.md # Tài liệu kỹ thuật scanner
── scanner_docs.md # Tài liệu kỹ thuật scanner
│ └── auto_flash_docs.md # Tài liệu kỹ thuật tự động hóa nạp FW
├── run.sh # Script khởi chạy (macOS/Linux)
├── run.bat # Script khởi chạy (Windows)
└── build_windows.bat # Script đóng gói thành .exe (Windows, PyInstaller)
@@ -89,31 +92,33 @@ Output: `dist\Mira_Firmware_Loader.exe` — không cần cài Python trên máy
│ Method: [ API (LuCI) | SSH (paramiko) ] │
│ Concurrent devices: [SpinBox] │
│ [ ⚡ FLASH SELECTED DEVICES ] │
│ ───────────────────────────────────────────────────── │
│ [ 🤖 Tự động hóa nạp FW ] │
└────────────────────────┬─────────────────────────────────┘
┌──────────────┼──────────────┐
│ │
┌──────▼──────┐ ┌────────▼────────────────┐
│ scanner.py │ │ Flash Workers
│ │
│ 1. Ping │ │ NewFlashThread
│ Sweep │ ├─ method=api
│ 2. arp -a │ │ └── api_flash.py
│ 3. Scapy │ │ └─ method=ssh │
│ ARP │ │ └── ssh_new_flash
└─────────────┘
UpdateFlashThread
│ └─ ssh_update_flash.py │
└─────────────────────────┘
┌──────────▼──────────┐
│ ssh_utils.py │
│ (Transport Layer) │
│ _create_ssh_client │
│ _upload_firmware │
│ _verify_firmware │
│ _sync_and_sysupgr │
└─────────────────────┘
─────────────────┼─────────────────
┌──────▼──────┐ ┌───────▼──────────┐ ┌───▼──────────────────
│ scanner.py │ Flash Workers │AutoFlashWorker │
│ │ (thủ công) │ │ (tự động hóa)
│ 1. Ping │
│ Sweep │ │ NewFlashThread Phase 1: Scan LAN
│ 2. arp -a │ ├─ api_flash (tối đa 15 lần)
│ 3. Scapy │ │ └─ ssh_new_flash Phase 2: Flash
│ ARP │ (auto-retry x3)
└─────────────┘ UpdateFlash ├─ api_flash
Thread│ └─ ssh_new_flash
│ └─ ssh_update │ └──────────────────────┘
──────────────────┘
┌──────────▼──────────┐
│ ssh_utils.py │
│ (Transport Layer) │
│ _create_ssh_client │
│ _upload_firmware │
│ _verify_firmware │
│ _sync_and_sysupgr │
└─────────────────────┘
```
---
@@ -138,7 +143,7 @@ Kết quả được merge theo IP và sort tăng dần trước khi trả về
- Mặc định ẩn gateway và IP máy tính đang chạy (có thể bật "Show all")
- Thiết bị đã flash trong session được đánh dấu "Already Flashed" và tự bỏ tick
### 3. Flash Firmware
### 3. Flash Firmware (Thủ công)
Có 2 chế độ và 2 method, tổng cộng 3 luồng thực thi khác nhau:
@@ -169,7 +174,73 @@ Luồng `ssh_update_flash.py`, SSH trực tiếp (không qua Telnet):
> ⚠️ Update Mode hiển thị cảnh báo nếu IP thiết bị khác `192.168.11.102` và yêu cầu xác nhận.
### 4. Xử lý song song
### 4. 🤖 Tự động hóa nạp FW (MỚI)
Tính năng nạp FW hoàn toàn tự động — chỉ cần cấu hình và nhấn bắt đầu:
```
Cấu hình → Auto Scan LAN → Phát hiện đủ thiết bị → Auto Flash → Auto Retry → Thông báo
```
#### 4.1. Quy trình
| Phase | Mô tả |
| --------------------- | ------------------------------------------------------------------------- |
| **Phase 1: Scan LAN** | Scan mạng liên tục mỗi 5 giây, tối đa **15 lần**, cho đến khi đủ thiết bị |
| **Phase 2: Flash** | Nạp FW song song qua ThreadPoolExecutor, tự động **retry tối đa 3 lần** |
#### 4.2. Cấu hình
| Tham số | Mô tả | Mặc định |
| --------------- | --------------------------------------------- | ------------------- |
| **Firmware** | File firmware (.bin/.hex/.uf2) | Lấy từ cửa sổ chính |
| **Mạng** | Dải mạng LAN cần scan | Tự suy từ IP host |
| **Số lượng** | Số thiết bị cần nạp | 5 |
| **Phương thức** | API (LuCI) hoặc SSH | API (LuCI) |
| **Song song** | Số thiết bị nạp cùng lúc (0 = không giới hạn) | 10 |
#### 4.3. Auto-Retry nạp FW
Khi một thiết bị nạp thất bại, hệ thống tự động retry:
```
Lần 1 → FAIL: Connection timeout
⚠️ Log cảnh báo, chờ 2 giây...
Lần 2 → FAIL: Upload error
⚠️ Log cảnh báo, chờ 2 giây...
Lần 3 → DONE ✅ (hoặc ❌ báo lỗi sau 3 lần)
```
- Tối đa **3 lần retry** mỗi thiết bị (`MAX_FLASH_RETRIES`)
- Chờ **2 giây** giữa mỗi lần retry để thiết bị ổn định
- Nếu hết 3 lần vẫn fail → đánh dấu ❌, tiếp tục thiết bị tiếp theo
#### 4.4. Scan Timeout
- Nếu scan **15 lần** mà chưa đủ thiết bị → dừng và hiện cảnh báo
- Gợi ý kiểm tra: thiết bị đã bật chưa, dải mạng có đúng không
#### 4.5. 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 | Chặn 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 | Tự động lọc khỏi kết quả scan |
#### 4.6. Lịch sử nạp
Kết quả nạp được lưu ở 2 cấp:
| Nơi lưu | Phạm vi | Format |
| ------------------------------- | ---------------------- | ------------------------------------ |
| `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ị cùng format ở cả 2 cửa sổ: `[HH:MM:SS] ✅/❌ IP (MAC) — result`
### 5. Xử lý song song
| Tham số | Mô tả |
| ---------------------- | ------------------------------------------------------------------------ |
@@ -188,6 +259,23 @@ Luồng `ssh_update_flash.py`, SSH trực tiếp (không qua Telnet):
| **SSH Password** | `admin123a` | Hardcoded, không hiển thị trên UI |
| **Concurrent devices** | `10` | Số luồng flash song song |
| **Show all** | Tắt | Ẩn gateway và IP máy host |
| **MAX_FLASH_RETRIES** | `3` | Số lần retry nạp FW (tự động) |
| **MAX_SCAN_ROUNDS** | `15` | Số lần scan tối đa (tự động) |
---
## 🛡️ 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 15 lần chưa đủ thiết bị | Hiện popup cảnh báo, dừng tự động |
| Flash thất bại lần 12 (tự động) | 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 an toàn |
| IP 192.168.11.102 + New Flash | Chặn ngay, hiện cảnh báo |
| 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 |
---