# 2026 NASA 3! CSIE Wi-Fi ## Meetings :::spoiler 3/17 #### 已完成 - 找出系館所有 AP - 討論要選那些點測試訊號 - 決定記錄 BSSID、RSSI、Channel、Rx/Tx Ra #### TODO - 測 AP 數據 ::: :::spoiler 3/20 #### 已完成 - 測 B1 的 AP - 測 1F 的 AP #### TODO - 補測 1F 某些教室的 AP ::: :::spoiler 4/3 #### 已完成 - 跟無線組組長開會 #### TODO - 期中前 - 做一個 UI 把之前測的數據放上去 - 期中後 - 把這個地圖改成動態 - 目標:讓使用者可以向 NASA 團隊回報壞掉的 AP、訊號不佳的情況 ::: :::spoiler 4/5 #### 已完成 - 完成網站的基本架構(使用 HTML) #### TODO - 導入 leaflet ::: :::spoiler 4/7 #### 已完成 - 導入 leaflet - 加入互動式功能 #### TODO - 改成 React ::: :::spoiler 4/10 #### 已完成 - 把網站前端改成 Vite + React #### TODO - 把網站搬到 VM 上 - 準備期中 demo ::: :::spoiler 4/19 #### 已完成 - 搬到 VM 上 - 做 demo 簡報 - 討論期中後的目標 - 錄 demo 影片 #### TODO - 完成 1F 的頁面 ::: :::spoiler 4/21 #### 已完成 - 1F 頁面 - 把 B1 的點補齊 - 寫了更新網頁的 shell script - 補完之前的會議紀錄 #### TODO - 和無線組組長討論期中目標 - 看看能不能要到 SNMP 的唯讀權限 ::: :::spoiler 4/28 #### 已完成 - 開會 - 問SNMP權限 - 要不要LDAP? 可能要 - 速度指標可以考慮用使用者測試到的速度/到計中的速度 - 架構 #### TODO - 寫後端🥲 ::: :::spoiler 5/5 #### 已完成 - 把單點的資訊改成熱力圖 - 新增二至五樓的頁面 - 新增測速功能 #### TODO - 寫API文件🥲 - 導入SNMP數據🥲 ::: :::spoiler 5/26 #### 已完成 - 進入 SNMP agent #### TODO - 期末 demo - ~~登入系統~~ - database 的 HA(備份、安全性) - SNMP 資料(做了測速系統但明顯無效) - webhook 回報 - 改成 UI/UX 組的地圖 - 製作AP點狀圖 ::: ## Workflow - Open an issue - Lables: `frontend` for frontend related issues, `backend` for backend related issues, `bug` for fix, `enhancement` for feature, etc. - Work on a branches other than `main` branch - Commit with propoer commit messages - Open a pull request - Merge into `main` if no diffs - Else, solve conficts - `git pull origin main` :::warning :warning: 記得要寫 Document ::: ## Job Distribution ### Layout ```wifi_backend/ ├── manage.py ├── requirements.txt ├── .env │ ├── config/ # Django project 總設定 │ ├── __init__.py │ ├── settings.py # 需在此設定 Celery 與 JWT 參數 │ ├── urls.py │ ├── asgi.py │ ├── wsgi.py │ └── celery.py # Celery 排程器的起始設定檔 │ ├── auth_api/ #處理 LDAP 登入與 JWT 核發 │ ├── __init__.py │ ├── services.py │ ├── views.py # 提供 /api/login 端點 │ └── urls.py │ ├── devices/ # AP 設備靜態資料 (SQLite) │ ├── models.py │ ├── serializers.py │ ├── views.py │ ├── urls.py │ └── admin.py │ ├── measurements/ # 測量結果與報修紀錄 (SQLite / InfluxDB) │ ├── models.py │ ├── serializers.py │ ├── views.py │ ├── urls.py │ └── admin.py │ ├── iperf_api/ # iperf 測速 API (主動測量) │ ├── __init__.py │ ├── services.py │ ├── serializers.py │ ├── views.py │ └── urls.py │ ├── snmp_api/ # SNMP 讀取 API (背景輪詢) │ ├── __init__.py │ ├── services.py │ ├── tasks.py # 定義每分鐘定時執行的 Celery Task │ ├── views.py # 提供給前端畫歷史折線圖的 API │ └── urls.py │ └── heatmap/ # 給前端 Leaflet 用的熱力圖 JSON ├── __init__.py ├── views.py └── urls.py ``` ## Data ::: spoiler B1 ### AP正下方 #### csie-5G |測點ID|測量時間|BSSID |Channel |RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-|-| |B02|0320.16:18|F8‑E7‑1E‑66‑45‑3C|36|-37|220.7|188.4|400|400| |B00|0320.16:33|30‑87‑D9‑71‑6B‑2C|44|-36|168.2|159.9|360|400| |B15|0320.16:42|30‑87‑D9‑71‑96‑4C|36|-39|194.4|194.4|360|400| |B04|0320.16:48|34‑8F‑27‑5E‑7A‑8C|116|-35|241.1|212.5|400|400| |B09|0320.17:00|30‑87‑D9‑71‑96‑EC|100|-57|150.3|176.4|270|324| |B05|0320.17:20|30‑87‑D9‑71‑7F‑CC|108|-36|218.2|275.9|360|400| #### csie |測點ID|測量時間|BSSID |Channel |RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-|-| |B02|0320.16:18|F8‑E7‑1E‑26‑45‑39|6|-37|49.2|38.2|144.4|144.4| |B00|0320.16:37|30‑87‑D9‑31‑6B‑29|1|-59|9.4|11.6|130|52| |B15|0320.16.41|30‑87‑D9‑31‑96‑49|1|-52|13.9|60|144|104| |B04|0320.16:46|34‑8F‑27‑1E‑7A‑89|6|-34|47.5|27.0|144|144| |B09|0320.16:57|30‑87‑D9‑31‑96‑E9|6|-34|41.7|24.3|144|144| |B05|0320.17:17|30‑87‑D9‑31‑7F‑C9|1|-35|19.4|4.2|65|144| ### 兩個AP中間 #### csie-5G |測點ID|測量時間|連到的AP|RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-| |M1|0320.17:25|B02|-59|114.0|108.7|270|240| |M2|0320.16:54|B15|-49|201.3|201.7|360|400| |M3|0320.17:05|B15|-44|178.2|194.9|360|360| |M4|0320.17:23|B15|-62|97.3|125.9|216|216| #### csie |測點ID|測量時間|連到的AP|RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-| |M1|0320.17:27|B02|-51|31.1|44.9|130|115| |M2|0320.16:50|B04|-40|14.1|18.4|130|117| |M3|0320.17:02|B04|-64|4.5|13.6|104|117| |M4|0320.17:22|B09|-49|36.2|16.2|144|130| ### 遠點 #### csie-5G |測點ID|測量時間|連到的AP|RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-| |R1|0320.17:28|B00|-57|133.9|115.5|324|300| |R2|0320.17:09|B15|-48|192.6|216.1|360|400| |R3|0320.17:11|B15|-56|166.8|170.4|270|243| #### csie |測點ID|測量時間|連到的AP|RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-| |R1|0320.17:29|B00|-63|6.6|5.5|104|117| |R2|0320.17:08|B09|-53|22.3|17.3|144|104| |R3|0320.17:10|B09|-52|37.2|17.4|117|130| ::: :::spoiler 1F ![IMG_0738](https://hackmd.io/_uploads/ryXW-H85bl.jpg) ### AP正下方 #### csie-5G |測點ID|測量時間|BSSID |Channel |RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-|-| |R102|0324.9:46|30‑87‑D9‑71‑79‑EC|108|-30|256.4|231.5|400|400| |R103(人多)|0324.13:15|30‑87‑D9‑71‑98‑CC|100|-40|172.2|159|400|400| |R106(有問題)|0324.9:55|30‑87‑D9‑71‑99‑4C|60|-62|141|157.7|270|270| |R110|0324.10:02|30‑87‑D9‑71‑52‑4C|132|-35|273.4|235.5|400|400| |R101|0324.10:18|30‑87‑D9‑71‑55‑4C|44|-34|250|241.3|400|400| |R104(人多)|0324.13:21|34‑8F‑27‑5A‑E4‑CC|116|-33|162.4|92.7|360|400| |R105|0324.10:19|30‑87‑D9‑31‑6B‑AC|36|-33|244.7|264.9|360|400| |R107|0324.10:28|30‑87‑D9‑71‑59‑8C|44|-40|253.4|236.3|400|400| |R111|0324.10:31|30‑87‑D9‑71‑83‑0C|132|-38|227.1|239.1|360|360| #### csie |測點ID|測量時間|BSSID |Channel |RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-|-| |R102|0324.9:44|30‑87‑D9‑31‑79‑E9|1|-41|40.1|31.1|130|130| |R104|0324.13:21|34‑8F‑27‑1A‑E4‑C9|11|-27|24.4|56.4|144|144| |R106(有問題)|0324.9:50|30‑87‑D9‑31‑52‑49|6|-60|25.7|27.2|144|78| |R110|0324.10:01|30‑87‑D9‑31‑52‑49|6|-25|68.4|35.4|130|144| |R101|0324.10:09|30‑87‑D9‑31‑55‑49|6|-31|43.4|41.7|144|130| |R105|0324.10:19|30‑87‑D9‑31‑6B‑A9|6|-29|55.5|31.8|144|144| |R107|0324.10:27|30‑87‑D9‑31‑59‑89|6|-40|49.7|27.3|130|144| |R111|0324.10:30|30‑87‑D9‑31‑83‑09|11|-31|37.0|54.3|144|144| ### 兩個AP中間 #### csie-5G |測點ID|測量時間|連到的AP|RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-| |M5|0324.10:56|R107|-54|212.0|231.3|324|360| |M6|0324.10:52|R107|-55|203.8|232.5|270|360| #### csie |測點ID|測量時間|連到的AP|RSSI(dBm) |Rx rate |Tx rate|Rx rate (PHY)|Tx rate (PHY)| | - | - | -| -|-|-|-|-| |M5|0324.10:52|R107|-49|42.3|28.5|130|144| |M6|0324.10:52|R111|-49|45.5|22.2|130|130| ::: ### 測量時的觀察 - 從舊館走到新管會先連到N3,N3跟N4需移動較遠的距離才會做切換 - 在N1下方可能會連到牆內的N1,導致訊號不佳 - N2,N3,N6不易切換 - 在M3,csie_5g連到B04很怪 - 在B05正下方會連到B09(B05_AP會閃黃燈)(csie的部分) - R106信號特別弱,很常連上後又斷掉(AP亮黃燈) - 手機不一定可以連到 - R104在紀錄時人有點多 ## API文件 :::spoiler heatmap ### POST /api/heatmap/measurements/create/ (新增一筆wifi測量資料) #### request body ```json { "floor": "basement", "point_id": "b00", "x": 65.2, "y": 51.3, "note": "新館空曠區域", "ssid": "csie-5G", "bssid": "xx:xx:xx:xx:xx:xx", "channel": 36, "rssi": -36, "rx_rate": 866.7, "tx_rate": 780.0 } ``` #### success response ```json { "message": "created", "data": { "id": 1, "floor": "basement", "point_id": "b00", "x": 65.2, "y": 51.3, "note": "新館空曠區域", "ssid": "csie-5G", "bssid": "xx:xx:xx:xx:xx:xx", "channel": 36, "rssi": -36, "rx_rate": 866.7, "tx_rate": 780.0, "measured_at": "2026-05-11T10:30:00+08:00" } } ``` #### error response ```json { "message": "invalid data", "errors": { "rssi": \["This field is required."] } } ``` ### GET /api/heatmap/measurements/ (取得wifi資料列表) |參數|說明|範例 |--|--|--| |floor|篩選樓層|basement,floor1 |ssid|篩選wifi名稱|csie,csie-5G| |bssid|篩選AP MAC位址|aa\:bb\:cc\:dd\:ee:ff| |limit|限制回傳筆數,預設500,最大2000|100| #### example request GET /api/heatmap/measurements/?floor=basement&ssid=csie-5G&limit=100 ### GET /api/heatmap/ (取得給前端heatmap的資料) |參數|說明|範例| |--|--|--| |floor|篩選樓層|basement,floor1| |ssid|篩選wifi名稱|csie,csie-5G| |bssid|篩選AP MAC位址|aa\:bb\:cc\:dd\:ee:ff| |min_rssi|篩選RSSI下限,保留大於等於此值的資料|-70| |max_rssi|篩選RSSI上限,保留小於等於此值的資料|-35| |limit|限制回傳筆數,預設 5000,最大 10000|1000| #### example request GET /api/heatmap/?floor=basement&ssid=csie-5G&min_rssi=-70&limit=1000 #### response ```json { "count": 1, "metric": "rssi", "coordinate": "xy-percent", "floor": "basement", "data": [ { "id": 1, "floor": "basement", "x": 65.2, "y": 51.3, "value": 1.0, "rssi": -36, "point_id": "b00", "note": "新館空曠區域", "ssid": "csie-5G", "bssid": "xx:xx:xx:xx:xx:xx", "channel": 36, "rx_rate": 866.7, "tx_rate": 780.0, "measured_at": "2026-05-11T10:30:00+08:00" } ] } ``` ### Heatmap Value `value` 是由 `rssi` 轉換而來,數值越大代表訊號越強。 例如: - RSSI = -36,value = 0.85 - RSSI = -60,value = 0.45 - RSSI = -90,value = 0.03 ::: :::spoiler client ### POST api/iperf/run (執行 iperf3 網路測速) #### request body | 參數 | 說明 | 範例 | | -------- | -------- | -------- | | target_ip | 目標設備的 IP 位址(須為合法的 IPv4/IPv6,且目標設備需運行 iperf3 -s) | "192.168.1.100" | | duration | 測量時間(秒),預設值為 5,限制範圍為 1 到 30 | 10 ```json { "target_ip": "192.168.1.100", "duration": 10 } ``` #### success response (HTTP 200 OK) ```josn { "success": true, "target_ip": "192.168.1.100", "download_mbps": 850.55 } ``` #### error response - Validation Error (HTTP 400 Bad Request) 當輸入不合法的 IP 格式或超出範圍的測量時間時回傳: ```josn { "target_ip": [ "Enter a valid IPv4 or IPv6 address." ] } ``` #### error response - Service Unavailable (HTTP 503 Service Unavailable) 當 iperf3 執行失敗(例如目標機器沒開 iperf3 -s)或連線逾時回傳: ```json { "success": false, "error": "連線失敗。請確認目標 IP 正確,且已執行 'iperf3 -s'。" } ``` > `error` 欄位的值也可能是 "測速連線逾時,目標機器未回應。" 或 "系統發生未預期錯誤。" ### GET /api/iperf/download/ (下載 100MB 的隨機檔案,用於 HTTP 下載測速) #### example request ```GET /api/iperf/download/``` #### response (HTTP 200 OK) - Content-Type: `application/octet-stream` - Response Body: 100MB 的隨機二進位資料 (Dummy data) - Headers: 包含強制禁止快取的標頭,確保每次測速都是實際走網路傳輸: - `Cache-Control`: `no-cache`, `no-store`, `must-revalidate` - `Pragma`: `no-cache` - `Expires`: `0` ::: ## REST API互動基本流程 proxmox上的vm -(HTTP request)-> Ruckus vSZ Controller REST API -(JSON response)-> ap解析資料