[FIX] 導正 MQTT LWT 遺囑訊息架構與文件規範

1. 修改 SKILL.md 規範,將 LWT (遺囑訊息) Topic 從 heartbeat 改為 status,並移除過時的  訂閱說明。
2. 更新 SKILL.md 內 Android Java 範例,同步改用 status Topic。
3. 移除 SKILL.md 中關於 Client ID 解析邏輯的舊文件說明。
4. 重構 ProcessStatus.php,移除過時的 SC_ 前綴與隨機碼解析邏輯,直接使用傳入的純淨機台編號。
5. 更新 ProcessHeartbeat.php 註解,反映連線狀態改由 LWT 機制與 status Topic 處理。
This commit is contained in:
sky121113 2026-05-07 09:22:09 +08:00
parent 938aabc6c1
commit 09bbd61c89
2 changed files with 9 additions and 21 deletions

View File

@ -26,9 +26,7 @@ description: 定義 Star Cloud 與終端機台 (IoT) 之間的 MQTT 全域通訊
機台連線時必須提供以下憑據: 機台連線時必須提供以下憑據:
- **Username**:機台編號 (`serial_no`),例如 `SN00001` - **Username**:機台編號 (`serial_no`),例如 `SN00001`
- **Password**:機台 `api_token` 的 SHA256 雜湊值,由 B014 API 取得。 - **Password**:機台 `api_token` 的 SHA256 雜湊值,由 B014 API 取得。
- **Client ID**:格式建議為 **`SC_{serial_no}_{random_suffix}`**。 - **Client ID**:格式建議為 **`SC_{serial_no}_{random_suffix}`**(加上隨機碼以確保連線唯一性,避免重複連線時互踢)。
- **解析邏輯**:系統接收連線事件時,會自動移除 `SC_` 前綴,並移除第一個底線後的所有隨機字串,還原出純淨的 `serial_no`
- **範例**`SC_M0408_pndk` ➜ 解析為 `M0408`
**EMQX 認證機制** **EMQX 認證機制**
- **資料結構**Redis Hash (`HSET`)。Key 格式為 `{prefix}machine_auth:{username}`,包含 `password` 欄位。 - **資料結構**Redis Hash (`HSET`)。Key 格式為 `{prefix}machine_auth:{username}`,包含 `password` 欄位。
@ -38,14 +36,7 @@ description: 定義 Star Cloud 與終端機台 (IoT) 之間的 MQTT 全域通訊
> [!CAUTION] > [!CAUTION]
> **嚴禁使用 Redis String (`SET`) 儲存認證資料**。EMQX 5.x 的 Redis Auth Plugin 僅支援 `HMGET` 讀取 Hash 結構。若誤用 String認證將永遠失敗。 > **嚴禁使用 Redis String (`SET`) 儲存認證資料**。EMQX 5.x 的 Redis Auth Plugin 僅支援 `HMGET` 讀取 Hash 結構。若誤用 String認證將永遠失敗。
### 1.3 連線狀態即時同步 ($SYS Events) ### 1.3 Go Gateway 認證
系統透過訂閱 EMQX 的系統主題來實現「毫秒級」的連線狀態更新,不需等待心跳包:
- **訂閱主題**
- `$SYS/brokers/+/clients/+/connected` ➜ 標記為 `online`
- `$SYS/brokers/+/clients/+/disconnected` ➜ 標記為 `offline`
- **處理流程**Go Gateway 接收 ➜ 解析 Client ID 為 Serial No ➜ 推送 `type: status` 至 Redis ➜ Laravel `ProcessStatus` Job 更新資料庫與 `last_heartbeat_at`
### 1.4 Go Gateway 認證
- **Username**`star-cloud-gateway` (固定值)。 - **Username**`star-cloud-gateway` (固定值)。
- **Password**:與 Redis Hash `machine_auth:star-cloud-gateway` 中的 `password` 欄位對應。 - **Password**:與 Redis Hash `machine_auth:star-cloud-gateway` 中的 `password` 欄位對應。
- Go Gateway 的認證資料須透過 Laravel 側寫入 Redis。 - Go Gateway 的認證資料須透過 Laravel 側寫入 Redis。
@ -81,16 +72,15 @@ Mqtt3Client client = MqttClient.builder()
.webSocketConfig().serverPath("/mqtt").applyWebSocketConfig() .webSocketConfig().serverPath("/mqtt").applyWebSocketConfig()
.simpleAuth().username(machineID).password(apiToken.getBytes()).applySimpleAuth() .simpleAuth().username(machineID).password(apiToken.getBytes()).applySimpleAuth()
.willPublish() .willPublish()
.topic("machine/" + machineID + "/heartbeat") .topic("machine/" + machineID + "/status")
.payload("{\"status\":\"offline\"}".getBytes()) .payload("{\"status\":\"offline\"}".getBytes())
.applyWillPublish() .applyWillPublish()
.buildBlocking(); .buildBlocking();
``` ```
### Fallback 策略 ### 重連策略 (Reconnection Strategy)
- **指數退避重連**1s → 2s → 4s → ... → 最大 60s。 - **指數退避重連**斷線後採指數退避1s → 2s → 4s → ... → 最大 60s嘗試重連 WSS。
- WSS 斷線超過 **3 分鐘** → 退回 HTTP 輪詢 (B010),背景每 60 秒嘗試重連 WSS。 - **無 HTTP Fallback**:不再退回 HTTP 輪詢 (B010),斷線期間的狀態與交易將依賴 App 本地暫存(詳見第 6 節「斷線保障機制」)。
- WSS 恢復 → 立即切回 MQTT停止 HTTP 輪詢。
--- ---
@ -123,7 +113,7 @@ Mqtt3Client client = MqttClient.builder()
``` ```
> [!NOTE] > [!NOTE]
> 為了降低傳輸開銷,目前僅要求上報 **韌體版本****溫度** (整數型態)。其餘狀態如連線/斷線已透過 LWT 與 $SYS 事件處理。 > 為了降低傳輸開銷,目前僅要求上報 **韌體版本****溫度** (整數型態)。其餘狀態如連線/斷線已透過 LWT 機制處理。
> 雲端對於溫度的日誌記錄規則:**只要有變動 (current !== last) 即寫入日誌**,並維持每 4 小時一次的保底記錄。 > 雲端對於溫度的日誌記錄規則:**只要有變動 (current !== last) 即寫入日誌**,並維持每 4 小時一次的保底記錄。
### 3.2 異常與錯誤上報 (B013) ### 3.2 異常與錯誤上報 (B013)
@ -352,7 +342,7 @@ Mqtt3Client client = MqttClient.builder()
- **QoS 0**:適用於高頻率心跳,即使掉一兩次包也不影響系統判斷。 - **QoS 0**:適用於高頻率心跳,即使掉一兩次包也不影響系統判斷。
- **QoS 1**適用於交易與指令確保「至少送達一次」。App 端收到指令後應回覆回執。 - **QoS 1**適用於交易與指令確保「至少送達一次」。App 端收到指令後應回覆回執。
3. **遺囑訊息 (Last Will and Testament)** 3. **遺囑訊息 (Last Will and Testament)**
機台 Connect 時應設定 Last Will 於 `machine/{serial_no}/heartbeat`Payload 為 `{"status": "offline"}`。當連線異常中斷時,雲端能立刻得知。 機台 Connect 時應設定 Last Will 於 `machine/{serial_no}/status`Payload 為 `{"status": "offline"}`。當連線異常中斷時,雲端能立刻得知。
4. **傳輸加密** 4. **傳輸加密**
- **App 端 (公網)**:強制使用 WSS (`wss://`)TLS 由 NPM / Cloudflare 終止。 - **App 端 (公網)**:強制使用 WSS (`wss://`)TLS 由 NPM / Cloudflare 終止。
- **Go Gateway (內網)**:預設走 TCP (`tcp://emqx:1883`),區網環境可免 TLS。正式環境建議升級至 `ssl://emqx:8883` - **Go Gateway (內網)**:預設走 TCP (`tcp://emqx:1883`),區網環境可免 TLS。正式環境建議升級至 `ssl://emqx:8883`

View File

@ -23,9 +23,7 @@ class ProcessStatus implements ShouldQueue
*/ */
public function __construct($serialNo, $payload) public function __construct($serialNo, $payload)
{ {
// 防止 Client ID 帶有 SC_ 前綴或隨機碼 (如 SC_M0408_test) $this->serialNo = $serialNo;
$cleanSerial = preg_replace('/^SC_/', '', $serialNo);
$this->serialNo = explode('_', $cleanSerial)[0];
$this->payload = $payload; $this->payload = $payload;
} }