# Quick Reference: Device-Specific Command Testing

## Module Structure

### `DaProductApp.TerminalManagement.MQTTCommandBuilder`

#### Device-Specific Builders:

| Function | Device | Input | Output |
|----------|--------|-------|--------|
| `build_mf919_command/1` | MF919 | `{command_type, url}` | JSON: `{type, command, requestId, downloadUrl}` |
| `build_sr600_command/1` | SR600 | `{path, url, file_name, ...}` | JSON: `{command, local_path, url, file_name, ...}` |
| `build_kozen_command/1` | Kozen | Same as SR600 | Same as SR600 |

#### Helper Functions:

```elixir
# File Categories per Device
MQTTCommandBuilder.get_file_categories("mf919")
# => [
#   {"params", "📦 Parameters (params.zip)"},
#   {"l3config", "⚙️ L3 Config (l3config.zip)"},
#   {"keys", "🔑 Keys (keys.json)"}
# ]

MQTTCommandBuilder.get_file_categories("sr600")
# => [
#   {"firmware", "🔧 Firmware"},
#   {"application", "📱 Application"},
#   {"config", "⚙️ Configuration"},
#   {"logo_image", "🖼️ Logo Image"}
# ]

# Command Types per Device
MQTTCommandBuilder.get_command_types("mf919")
# => [
#   {"UPDATE_PARAMS", "Update Parameters"},
#   {"UPDATE_L3_CONFIG", "Update L3 Config"},
#   {"LOAD_KEYS", "Load Keys"}
# ]

# URL Hints
MQTTCommandBuilder.get_url_hint("mf919", "params")
# => "http://demo.ctrmv.com/ota/mf919/params.zip"

# Generate Request ID
MQTTCommandBuilder.generate_request_id()
# => "req-1705945627-847263"

# Parameter Validation
MQTTCommandBuilder.validate_device_params("mf919", params)
# => {:ok, params} or {:error, "Missing required field..."}
```

## Example Usage

### MF919 Command Building:

```elixir
params = %{
  "command_type" => "UPDATE_PARAMS",
  "url_path_from_download" => "http://demo.ctrmv.com/ota/mf919/params.zip",
  "request_id" => "req-1705945627-847263"
}

{:ok, json_payload} = DaProductApp.TerminalManagement.MQTTCommandBuilder.build_mf919_command(params)

# Result:
# {
#   "type": "tms_command",
#   "command": "UPDATE_PARAMS",
#   "requestId": "req-1705945627-847263",
#   "downloadUrl": "http://demo.ctrmv.com/ota/mf919/params.zip"
# }
```

### SR600 Command Building:

```elixir
params = %{
  "local_path_to_save" => "firmware",
  "url_path_from_download" => "https://example.com/firmware.bin",
  "file_name" => "firmware.bin",
  "file_category" => "firmware",
  "merchant_config" => "true",
  "request_id" => "req-1705945627-847263"
}

{:ok, json_payload} = DaProductApp.TerminalManagement.MQTTCommandBuilder.build_sr600_command(params)

# Result:
# {
#   "command": "file_download",
#   "local_path_to_save": "firmware",
#   "url_path_from_download": "https://example.com/firmware.bin",
#   "file_name": "firmware.bin",
#   "file_category": "firmware",
#   "merchant_config": "true",
#   "retry_count": "3",
#   "request_id": "req-1705945627-847263"
# }
```

### Router (Automatic Dispatch):

```elixir
# MF919
{:ok, payload} = DaProductApp.TerminalManagement.MQTTCommandBuilder.build_command(
  "mf919", 
  %{"command_type" => "UPDATE_PARAMS", "url_path_from_download" => "..."}
)

# SR600
{:ok, payload} = DaProductApp.TerminalManagement.MQTTCommandBuilder.build_command(
  "sr600", 
  %{"local_path_to_save" => "firmware", "url_path_from_download" => "..."}
)

# Kozen
{:ok, payload} = DaProductApp.TerminalManagement.MQTTCommandBuilder.build_command(
  "kozen", 
  %{"local_path_to_save" => "firmware", ...}
)
```

## Handler Flow (index.ex)

### Current Handler: `send_file_download`

```elixir
# Flow:
1. Extract terminal from socket
2. Extract model from terminal
3. Validate params using MQTTCommandBuilder.validate_device_params/2
4. Generate request_id using MQTTCommandBuilder.generate_request_id/0
5. Build payload using MQTTCommandBuilder.build_command/2
6. Publish to MQTT topic: /ota/{product_key}/{serial}/update
7. Return success/error flash message
```

### Error Handling:

| Error | Message | Cause |
|-------|---------|-------|
| No terminal | "No terminal selected" | Device panel not open |
| Validation fail | "Missing required field for {MODEL}: {field}" | Parameter validation |
| Build fail | "Failed to build command: {reason}" | JSON encoding error |
| Publish fail | "Failed to send command: {reason}" | MQTT broker unavailable |

## UI Form Behavior

### MF919 Terminal Selected:
```
Device Badge: [MF919]

Command Type *:         <- Dropdown with UPDATE_PARAMS, UPDATE_L3_CONFIG, LOAD_KEYS
[SELECT command_type]

Download URL *:         <- Text input for URL
[url_path_from_download]

Helper Box:
  Available URLs:
  • params.zip: http://demo.ctrmv.com/ota/mf919/params.zip
  • l3config.zip: http://demo.ctrmv.com/ota/mf919/l3config.zip
  • keys.json: http://demo.ctrmv.com/ota/mf919/keys.json

[Send MF919 Command]
```

### SR600/Other Terminal Selected:
```
Device Badge: [SR600]

Download URL:
[url_path_from_download]

File Name:              Local Save Path:
[file_name]             [exdata|config|firmware|apps]

File Category:                  Is Merchant Config:
[firmware|application|          [x] Merchant Config
 config|logo_image|
 keys|parameters|emv]

[Send SR600 Command]
```

## Testing MQTT Payload

### Verify MF919 Payload:
```bash
mosquitto_sub -h localhost -t "/ota/pFppbioOCKlo5c8E/+/update" -v

# When sending UPDATE_PARAMS, expect:
# /ota/pFppbioOCKlo5c8E/{serial}/update {
#   "type":"tms_command",
#   "command":"UPDATE_PARAMS",
#   "requestId":"req-...",
#   "downloadUrl":"http://demo.ctrmv.com/ota/mf919/params.zip"
# }
```

### Verify SR600 Payload:
```bash
mosquitto_sub -h localhost -t "/ota/pFppbioOCKlo5c8E/+/update" -v

# When sending file_download, expect:
# /ota/pFppbioOCKlo5c8E/{serial}/update {
#   "command":"file_download",
#   "local_path_to_save":"firmware",
#   "url_path_from_download":"...",
#   "file_name":"...",
#   "file_category":"firmware",
#   "merchant_config":"true",
#   "retry_count":"3",
#   "request_id":"req-..."
# }
```

## Files Modified

1. **Created**: `lib/da_product_app/terminal_management/mqtt_command_builder.ex`
   - 178 lines
   - Device-specific builders
   - Helper functions
   - Validation logic

2. **Modified**: `lib/da_product_app_web/live/terminal_live/index.ex`
   - Updated `handle_event("send_file_download", ...)`
   - Added `send_mqtt_command/4`
   - Device model awareness

3. **Modified**: `lib/da_product_app_web/live/terminal_live/index.html.heex`
   - Conditional form rendering
   - MF919 vs SR600 UI
   - Enhanced file categories
   - Device badge

## Configuration

### MQTT Settings:
- **Broker**: localhost:1883
- **Topic Format**: `/ota/{product_key}/{device_serial}/update`
- **Default Product Key**: `pFppbioOCKlo5c8E`
- **QoS**: 1 (At least once delivery)

### Device URLs:
- **MF919**: http://demo.ctrmv.com/ota/mf919/
- **SR600**: http://demo.ctrmv.com/ota/sr600/

## Logs

All device commands are logged at INFO level:
```
[info] MF919 MQTT Command: %{"command" => "UPDATE_PARAMS", "downloadUrl" => "...", "requestId" => "...", "type" => "tms_command"}
[info] SR600 MQTT Command: %{"command" => "file_download", ...}
[info] Sending mf919 command to {serial} on topic: /ota/pFppbioOCKlo5c8E/{serial}/update
```

Enable debug logging to see command payload construction details.
