> For the complete documentation index, see [llms.txt](https://api.intecular.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api.intecular.com/invisoutlet-pro/ota/perform-ota-update.md).

# Perform OTA Update

\[TCP/WebSocket <--> InvisOutlet]

> Perform an OTA update for InvisOutlet, InvisDeco, or both devices as one ordered full update.

## Request

* <mark style="color:red;">`packetID`</mark>: The packet ID. This can be any six-digit number with no leading zeros.
* <mark style="color:red;">`payload`</mark>:&#x20;
  * <mark style="color:red;">`callbackName`</mark>: 21
  * <mark style="color:red;">`callbackArgs`</mark> :&#x20;
    * `1` : Update target; 1 - InvisOutlet only, 2 - InvisDeco only, 3 - Update all (InvisDeco first, then InvisOutlet)
    * `2` : InvisDeco update method; 0 - Update via Wi-Fi, 1 - Update via InvisOutlet

{% hint style="info" %}
The update method value is ignored when the target is `1`.
{% endhint %}

| `callbackArgs` | Operation                                                               |
| -------------- | ----------------------------------------------------------------------- |
| `[1,0]`        | Update InvisOutlet over Wi-Fi                                           |
| `[2,0]`        | Update InvisDeco over Wi-Fi                                             |
| `[2,1]`        | Update InvisDeco through InvisOutlet.                                   |
| `[3,0]`        | Update all: InvisDeco over Wi-Fi, then InvisOutlet over Wi-Fi           |
| `[3,1]`        | Update all: InvisDeco through InvisOutlet, then InvisOutlet over Wi-Fi. |

{% hint style="info" %}
Use `[3,0]` for the normal update-all flow. If InvisDeco Wi-Fi is unreliable, or if InvisDeco must be force-updated, use `[3,1]`.
{% endhint %}

{% hint style="warning" %}
`[3,1]` always transfers the InvisDeco image via InvisOutlet. The InvisDeco will be updated regardlessly if the firmware version is already up-to-date.
{% endhint %}

### Update all using InvisDeco Wi-Fi

```json
{
    "packetID": 414883,
    "payload": {
        "callbackName": 21,
        "callbackArgs": [3, 0]
    }
}
```

### Update all using InvisDeco via InvisOutlet

```json
{
    "packetID": 414884,
    "payload": {
        "callbackName": 21,
        "callbackArgs": [3, 1]
    }
}
```

## Update-all sequence

For target `3`, InvisOutlet treats both device updates as one ordered transaction:

1. InvisDeco starts using the selected update method.
2. When InvisDeco succeeds, InvisOutlet starts its update over Wi-Fi.
3. If InvisDeco is already up-to-date during `[3,0]`, its stage is treated as a successful no-op and InvisOutlet still starts.
4. If InvisDeco fails, the pending InvisOutlet stage is cancelled.

InvisOutlet owns the handoff. A client must not send a second callback `21` request after receiving the successful InvisDeco result.

If InvisOutlet loses power or unexpectedly restarts before the transaction finishes, refresh both firmware versions and issue a new request if required.

Progress and result events are emitted separately for each device. Clients receive InvisDeco events first (`callbackArgs[0] = 2`), followed by InvisOutlet events (`callbackArgs[0] = 1`). When an InvisOutlet WWW partition update is included, its events use `callbackArgs[0] = 3`.

{% hint style="info" %}
An already-current InvisDeco may complete its `[3,0]` stage without download-progress events. Wait for the InvisDeco result, then continue listening for InvisOutlet events.
{% endhint %}

## Immediate response

The immediate response confirms whether the request was accepted.

* <mark style="color:red;">`sn`</mark>: InvisOutlet serial number.
* <mark style="color:red;">`packetID`</mark>: The request packet ID.
* <mark style="color:red;">`PUBACK`</mark>:
  * `1` — Request accepted and the first stage will start.
  * `0` — Request rejected or could not initialize. Target `3` is also rejected when InvisDeco is offline, the arguments are invalid, or another OTA transaction is active.

```json
{
    "sn": "0003C44076",
    "packetID": 414883,
    "PUBACK": 1
}
```

## Synchronous stage-start response

* <mark style="color:red;">`payload.callbackName`</mark>: `21`
* <mark style="color:red;">`payload.callbackArgs[0]`</mark>: Device whose OTA stage is starting.
  * `1` — InvisOutlet
  * `2` — InvisDeco
* <mark style="color:red;">`payload.callbackArgs[1]`</mark>:
  * `1` — OTA stage can continue
  * `0` — OTA stage failed to initialize

```json
{
    "sn": "0003C44076",
    "packetID": 301551,
    "payload": {
        "callbackName": 21,
        "callbackArgs": [2, 1]
    }
}
```

For an accepted update-all request, the normal order is:

1. InvisDeco stage-start/progress/result events with device role `2`.
2. InvisOutlet stage-start/progress/result events with device role `1`.
3. Optional InvisOutlet WWW progress/result events with role `3`, when a WWW update is included.

A successful InvisDeco result is an intermediate result, not completion of the update-all operation.

{% hint style="info" %}
InvisOutlet revB disconnects and reboots while installing OTA firmware. Reconnect the TCP client and continue listening, but do not automatically resend callback `21`.
{% endhint %}

{% hint style="info" %}
Follow the transaction through [OTA Download Progress (Synchronous)](/invisoutlet-pro/ota/ota-download-progress-synchronous.md) and [OTA Result Update (Synchronous)](/invisoutlet-pro/ota/ota-result-update-synchronous.md). Synchronous messages use newly generated packet IDs, not the original request packet ID.
{% endhint %}
