'Star Cloud IoT 通訊協議', 'version' => 'v1.0.0', 'description' => '此文件提供 Star Cloud 智能販賣機 IoT 端點通訊協議說明,包含主動拉取 (HTTP REST) 與被動接收 (MQTT) 雙軌通訊機制,供硬體端與前端開發者調研與串接使用。', 'http_apis' => [ [ 'name' => '機台核心通訊 (IoT Core)', 'apis' => [ [ 'name' => 'B000: 維運人員登入認證 (Technician Login)', 'slug' => 'b000-tech-login', 'method' => 'POST', 'path' => '/api/v1/app/admin/login/B000', 'description' => '機台啟動引導的第一步。維運人員輸入個人帳密與機台編號進行認證,成功後核發臨時 Sanctum Token 供後續 B014 下載敏感設定使用。', 'headers' => [ 'Content-Type' => 'application/json', ], 'parameters' => [ 'username' => [ 'type' => 'string', 'required' => true, 'description' => '維運人員帳號', 'example' => 'admin_test' ], 'password' => [ 'type' => 'string', 'required' => true, 'description' => '維運人員密碼', 'example' => 'password123' ], 'machine' => [ 'type' => 'string', 'required' => true, 'description' => '機台序號 (Serial No)', 'example' => 'SN202604130001' ], ], 'response_parameters' => [ 'message' => [ 'type' => 'string', 'description' => '回應訊息', 'example' => 'Success' ], 'token' => [ 'type' => 'string', 'description' => '臨時身份認證 Token (Sanctum)', 'example' => '1|abcdefg...' ], ], 'request' => [ 'username' => 'admin_test', 'password' => 'password123', 'machine' => 'SN202604130001' ], 'response' => [ 'message' => 'Success', 'token' => '1|abcdefg...' ], ], [ 'name' => 'B014: 機台參數與金鑰下載 (Config Download)', 'slug' => 'b014-config-download', 'method' => 'GET', 'path' => '/api/v1/app/machine/setting/B014', 'description' => '機台引導階段的第二步。在人員登入後,透過此介面下載金流金鑰、電子發票設定與機台專屬通訊 Token。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [ 'machine' => [ 'type' => 'string', 'required' => true, 'description' => '機台序號', 'example' => 'SN202604130001' ], ], 'response_parameters' => [ 'success' => [ 'type' => 'boolean', 'description' => '是否成功', 'example' => true ], 'data' => [ 'type' => 'array', 'description' => '配置物件陣列。包含:t050v01 (序號), api_token (通訊 Token), t050v41~43 (玉山設定), t050v34~38 (發票設定), TP_... (趨勢/手機支付設定)', 'example' => [ [ 't050v01' => 'SN202604130001', 'api_token' => 'mac_token_...', 't050v41' => '80812345', 't050v34' => '2000132', 'TP_APP_ID' => 'GP_001' ] ] ], ], 'request' => [], 'response' => [ 'success' => true, 'code' => 200, 'data' => [ [ 't050v01' => 'SN202604130001', 'api_token' => 'mac_token_...', 't050v41' => '80812345', 't050v42' => '9001', 't050v43' => 'hash_key', 't050v34' => '2000132', 'TP_APP_ID' => 'GP_001' ] ] ], 'notes' => '此 API 受 auth:sanctum 保護,必須在 Header 帶上從 B000 取得的 Token。' ], [ 'name' => 'B005: 廣告清單同步 (Ad Sync)', 'slug' => 'b005-ad-sync', 'method' => 'GET', 'path' => '/api/v1/app/machine/ad/B005', 'description' => '用於機台端獲取目前應播放的廣告檔案 URL 清單。此介面無需 Request Body。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [], 'response_parameters' => [ 'success' => [ 'type' => 'boolean', 'description' => '請求是否成功', 'example' => true ], 'code' => [ 'type' => 'integer', 'description' => '內部業務狀態碼', 'example' => 200 ], 'data' => [ 'type' => 'array', 'description' => '廣告物件陣列。內部欄位包含:t070v01 (名稱), t070v02 (秒數), t070v03 (位置:1:販賣頁, 2:來店禮, 3:待機廣告), t070v04 (URL), t070v05 (順位)', 'example' => [ [ 't070v01' => '測試機台廣告', 't070v02' => 15, 't070v03' => 3, 't070v04' => 'https://example.com/ad1.mp4', 't070v05' => 1 ] ] ], ], 'request' => [], 'response' => [ 'success' => true, 'code' => 200, 'message' => 'OK', 'data' => [ [ 't070v01' => '測試機台廣告', 't070v02' => 15, 't070v03' => 3, 't070v04' => 'https://example.com/ad1.mp4', 't070v05' => 1 ] ] ], ], [ 'name' => 'B009: 貨道庫存即時回報 (Inventory Report)', 'slug' => 'b009-inventory-report', 'method' => 'PUT', 'path' => '/api/v1/app/products/supplementary/B009', 'description' => '當人員在機台端完成操作後,將目前的貨道實體狀態同步回雲端。需進行 RBAC 權限核查。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [ 'account' => [ 'type' => 'string', 'required' => true, 'description' => '操作人員帳號', 'example' => '0999123456' ], 'data' => [ 'type' => 'array', 'required' => true, 'description' => '貨道數據陣列。tid: 貨道號, t060v00: 商品 ID, num: 庫存量', 'example' => [ ['tid' => '1', 't060v00' => '1', 'num' => '10'] ] ], ], 'response_parameters' => [ 'success' => [ 'type' => 'boolean', 'description' => '同步是否成功', 'example' => true ], 'code' => [ 'type' => 'integer', 'description' => '內部業務狀態碼', 'example' => 200 ], 'message' => [ 'type' => 'string', 'description' => '回應訊息', 'example' => 'Slot report synchronized success' ], 'status' => [ 'type' => 'string', 'description' => '固定回傳 49 代表同步完成', 'example' => '49' ], ], 'request' => [ 'account' => '0999123456', 'data' => [ ['tid' => '1', 't060v00' => '1', 'num' => '10'] ] ], 'response' => [ 'success' => true, 'code' => 200, 'message' => 'Slot report synchronized success', 'status' => '49' ], ], [ 'name' => 'B012: 商品配置與商品主檔同步 (Unified Sync)', 'slug' => 'b012-unified-sync', 'method' => 'GET', 'path' => '/api/v1/app/machine/products/B012', 'description' => '用於機台端獲取目前所有可販售商品的詳細配置 (全量同步)。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [], 'response_parameters' => [ 'success' => [ 'type' => 'boolean', 'description' => '請求是否處理成功', 'example' => true ], 'code' => [ 'type' => 'integer', 'description' => '內部業務狀態碼', 'example' => 200 ], 'data' => [ 'type' => 'array', 'description' => '商品明細物件陣列', 'example' => [ [ 't060v00' => '1', 't060v01' => '可口可樂 330ml', 't060v01_en' => 'Coca Cola', 't060v01_jp' => 'コカコーラ', 't060v03' => 'Cold Drink', 't060v06' => 'https://.../coke.png', 't060v09' => 25.0, 't060v11' => 10, 't060v30' => 20.0, 't063v03' => 25.0, 't060v40' => 'Buy 1 Get 1', 't060v41' => 'SKU-001', 'spring_limit' => 10, 'track_limit' => 15 ] ] ] ], 'request' => [], 'response' => [ 'success' => true, 'code' => 200, 'message' => 'OK', 'data' => [ [ 't060v00' => '1', 't060v01' => '可口可樂 330ml', 't060v01_en' => 'Coca Cola', 't060v01_jp' => 'コカコーラ', 't060v03' => 'Cold Drink', 't060v06' => 'https://.../coke.png', 't060v09' => 25.0, 't060v11' => 10, 't060v30' => 20.0, 't063v03' => 25.0, 't060v40' => 'Buy 1 Get 1', 't060v41' => 'SKU-001', 'spring_limit' => 10, 'track_limit' => 15 ] ] ], 'notes' => '運作邏輯 (Client-side Logic): GET 執行全量同步,App 應於收到成功回應後,先執行 deleteAll() 再進行 insertAll()。PATCH 執行增量更新,App 僅對記憶體中的既存商品進行欄位值覆蓋 (Patching)。' ], [ 'name' => 'B017: 貨道庫存同步 (Slot Synchronization)', 'slug' => 'b017-slot-sync', 'method' => 'GET', 'path' => '/api/v1/app/machine/reload_msg/B017', 'description' => '用於機台端獲獲取所有貨道的最新庫存、效期與狀態。通常由 B010 回傳 status: 49 時觸發。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [], 'response_parameters' => [ 'success' => [ 'type' => 'boolean', 'description' => '是否成功', 'example' => true ], 'data' => [ 'type' => 'array', 'description' => '貨道數據陣列。', 'example' => [ [ 'tid' => '1', 'num' => 10, 'expiry_date' => '2026-12-31', 'batch_no' => 'B2026', 'status' => '1' ] ] ], ], 'request' => [], 'response' => [ 'success' => true, 'code' => 200, 'data' => [ [ 'tid' => '1', 'num' => 10, 'expiry_date' => '2026-12-31', 'batch_no' => 'B2026', 'product_id' => 1, 'capacity' => 15, 'status' => '1' ] ] ], 'notes' => 'B017 為全量同步。實作上後端會依據 slot_no 進行排序,並將相關指令狀態更新為已完成。' ], [ 'name' => 'B024: 取貨碼/通行碼驗證與消耗回報', 'slug' => 'b024-access-code', 'method' => 'POST', 'path' => '/api/v1/app/sell/access-code/B024', 'description' => '處理代碼取貨流程。POST 用於驗證碼有效性,PUT 用於回報出貨成功並消耗代碼。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [ 'passCode' => [ 'type' => 'string', 'description' => '取貨碼 (POST)', ], 'accessCodeId' => [ 'type' => 'string', 'description' => '代碼 ID (PUT)', ], 'status' => [ 'type' => 'string', 'description' => '出貨狀態 (PUT: 1:成功, 0:失敗)', ], ], 'response_parameters' => [ 'res1' => ['type' => 'string', 'description' => '雲端關聯 ID'], 'res3' => ['type' => 'string', 'description' => '預計出貨商品 ID'], ], 'request' => [ 'passCode' => '12345678' ], 'response' => [ 'success' => true, 'res1' => '99', 'res3' => '5' ], ], [ 'name' => 'B027: 贈品碼/優惠券驗證與消耗回報', 'slug' => 'b027-freebie-code', 'method' => 'POST', 'path' => '/api/v1/app/sell/free-gift/B027', 'description' => '處理贈品券與 0 元購活動。邏輯與 B024 相似但對象為行銷贈品。', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], 'parameters' => [ 'passCode' => [ 'type' => 'string', 'description' => '贈品碼 (POST)', ], ], 'response_parameters' => [ 'success' => ['type' => 'boolean', 'description' => '驗證結果'], ], 'request' => [ 'passCode' => 'FREE888' ], 'response' => [ 'success' => true, 'message' => 'Free gift verified' ], ], ] ] ], 'mqtt_topics' => [ [ 'name' => '指令與通訊 (Commands & Flow)', 'topics' => [ [ 'name' => '機台心跳上報 (Heartbeat)', 'slug' => 'mqtt-heartbeat', 'action' => 'PUB', 'topic' => 'machine/{serial_no}/heartbeat', 'qos' => 0, 'description' => '機台每分鐘固定上報的狀態大包裝。整合了溫度與韌體版本。雲端記錄規則:溫度只要有變動 (current !== last) 即記錄日誌。', 'payload_parameters' => [ 'temperature' => ['type' => 'integer', 'description' => '目前機台溫度'], 'firmware_version' => ['type' => 'string', 'description' => 'APP 韌體版本'], ], 'payload_example' => [ 'temperature' => 20, 'firmware_version' => '2.1.6' ], ], [ 'name' => '機台異常上報 (Error)', 'slug' => 'mqtt-error', 'action' => 'PUB', 'topic' => 'machine/{serial_no}/error', 'qos' => 1, 'description' => '當機台發生硬體故障(如卡貨、通訊中斷)時即時上報。', 'payload_parameters' => [ 'tid' => ['type' => 'integer', 'description' => '貨道編號或任務 ID'], 'error_code' => ['type' => 'string', 'description' => '硬體錯誤代碼 (如 0403 代表卡貨)'], ], 'payload_example' => [ 'tid' => 12, 'error_code' => '0403' ], ], [ 'name' => '交易生命週期上報 (Transaction)', 'slug' => 'mqtt-transaction', 'action' => 'PUB', 'topic' => 'machine/{serial_no}/transaction', 'qos' => 1, 'description' => '整合交易生命週期的三個階段:交易建立 (create)、發票開立 (invoice) 以及出貨結果 (dispense)。', 'payload_parameters' => [ 'action' => ['type' => 'string', 'description' => '生命週期動作 (create, invoice, dispense)'], 'payment_type' => ['type' => 'string', 'description' => '支付方式 (action 為 create 時必填)'], 'amount' => ['type' => 'number', 'description' => '交易金額 (create/invoice 時使用)'], 'slot_no' => ['type' => 'string', 'description' => '出貨貨道號碼'], 'invoice_no' => ['type' => 'string', 'description' => '發票號碼 (action 為 invoice 時必填)'], 'status' => ['type' => 'string', 'description' => '出貨結果狀態 (action 為 dispense 時必填,如 success, failed)'], ], 'payload_example' => [ 'action' => 'create', 'payment_type' => 'credit_card', 'amount' => 25.0, 'slot_no' => '3', 'product_id' => '5' ], ], [ 'name' => '指令下發:遠端出貨 (Dispense)', 'slug' => 'mqtt-command-dispense', 'action' => 'SUB', 'topic' => 'machine/{serial_no}/command', 'qos' => 1, 'description' => '雲端主動下發「遠端出貨」指令。機台收到後應立即驅動馬達進行出貨,出貨完成或失敗後回報 ACK。', 'payload_parameters' => [ 'command' => ['type' => 'string', 'description' => '固定為 "dispense"'], 'command_id' => ['type' => 'string', 'description' => '指令唯一 ID'], 'payload' => ['type' => 'object', 'description' => '出貨參數'], 'payload.slot_no' => ['type' => 'string', 'description' => '欲出貨的貨道號碼'], 'payload.old_stock' => ['type' => 'integer', 'description' => '出貨前的庫存量'], 'payload.new_stock' => ['type' => 'integer', 'description' => '出貨後應剩餘的庫存量 (樂觀扣減結果)'], ], 'payload_example' => [ 'command' => 'dispense', 'command_id' => '9988776655', 'payload' => [ 'slot_no' => '1', 'old_stock' => 10, 'new_stock' => 9 ] ], ], [ 'name' => '指令下發:庫存同步 (Update Inventory)', 'slug' => 'mqtt-command-update-inventory', 'action' => 'SUB', 'topic' => 'machine/{serial_no}/command', 'qos' => 1, 'description' => '雲端主動下發「庫存更新」指令 (如從後台修改庫存、效期時觸發)。', 'payload_parameters' => [ 'command' => ['type' => 'string', 'description' => '固定為 "update_inventory"'], 'command_id' => ['type' => 'string', 'description' => '指令唯一 ID'], 'payload' => ['type' => 'object', 'description' => '更新參數'], 'payload.data' => ['type' => 'array', 'description' => '欲更新的貨道資料陣列'], 'payload.data[].slot_no' => ['type' => 'string', 'description' => '貨道號碼'], 'payload.data[].stock' => ['type' => 'integer', 'description' => '最新庫存量'], 'payload.data[].expiry_date' => ['type' => 'string', 'description' => '最新效期 (YYYY-MM-DD)'], 'payload.data[].batch_no' => ['type' => 'string', 'description' => '批號 (可為 null)'], ], 'payload_example' => [ 'command' => 'update_inventory', 'command_id' => '5566778899', 'payload' => [ 'data' => [ [ 'slot_no' => '1', 'stock' => 10, 'expiry_date' => '2026-12-31', 'batch_no' => null ] ] ] ], ], [ 'name' => '指令下發:遠端找零 (Change)', 'slug' => 'mqtt-command-change', 'action' => 'SUB', 'topic' => 'machine/{serial_no}/command', 'qos' => 1, 'description' => '雲端主動下發「找零」指令。指示機台退還指定金額的現金。', 'payload_parameters' => [ 'command' => ['type' => 'string', 'description' => '固定為 "change"'], 'command_id' => ['type' => 'string', 'description' => '指令唯一 ID'], 'payload' => ['type' => 'object', 'description' => '找零參數'], 'payload.amount' => ['type' => 'integer', 'description' => '欲找零/退款的金額'], ], 'payload_example' => [ 'command' => 'change', 'command_id' => '1122334455', 'payload' => [ 'amount' => 50 ] ], ], [ 'name' => '指令下發:系統控制 (System Control)', 'slug' => 'mqtt-command-system', 'action' => 'SUB', 'topic' => 'machine/{serial_no}/command', 'qos' => 1, 'description' => '雲端主動下發的系統級別控制指令。包含重啟、設備鎖定解鎖、購物車結帳等無額外參數的指令。', 'payload_parameters' => [ 'command' => ['type' => 'string', 'description' => '系統指令類型。支援:reboot (重啟機台), reboot_card (重啟刷卡機), checkout (購物車結帳), lock (設備鎖定), unlock (設備解鎖)'], 'command_id' => ['type' => 'string', 'description' => '指令唯一 ID'], 'payload' => ['type' => 'object', 'description' => '空物件 (無額外參數)'], ], 'payload_example' => [ 'command' => 'reboot', 'command_id' => '9999999999', 'payload' => new \stdClass() ], ], [ 'name' => '指令執行回報 (Machine to Cloud)', 'slug' => 'mqtt-command-ack', 'action' => 'PUB', 'topic' => 'machine/{serial_no}/command/ack', 'qos' => 1, 'description' => '機台執行完雲端指令後的主動回報。此回報極為重要,雲端將依此決定交易是否完成或需進行庫存回滾。', 'payload_parameters' => [ 'command_id' => ['type' => 'string', 'description' => '對應下發時的指令 ID'], 'result' => ['type' => 'string', 'description' => '執行結果,僅接受: success 或 failed'], 'stock' => ['type' => 'integer', 'description' => '執行指令後的最終剩餘庫存 (選填,通常出貨指令需帶上)'], 'message' => ['type' => 'string', 'description' => '額外的錯誤訊息 (選填)'], ], 'payload_example' => [ 'command_id' => '12345', 'result' => 'success', 'stock' => 9 ], ] ] ] ] ];