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