Skip to content

Core Ota Firmware Update

Mr.P edited this page Aug 29, 2026 · 3 revisions

Device Firmware Update

Device OTA updates the main firmware running on a supported AIBuds device. It is separate from Camera OTA, which updates the device's camera module.

The host app supplies a compatible local firmware package after completing its own update check, download, integrity verification, and device-model validation. The SDK transfers and installs that package, reports startup success, streams progress from 0.0 to 1.0, and returns the final upgrade result with the average transfer speed. Treat startHandler only as confirmation that the OTA task started; use completionHandler as the authoritative final result.

Device OTA delivery path

Validate the product input first, then let the SDK start, transfer, and complete the main-firmware update.

  1. Validate Package — Verify integrity, firmware compatibility, and the readable local path.
  2. Check Battery — Compare the current device battery with otaBatteryLimit immediately before starting.
  3. Select Protocol — Use the default overload or the product-required OTA protocol configuration.
  4. Start OTA Task — Submit the local package and distinguish start acceptance from final success.
  5. Transfer & Install — Keep the connection stable while normalized progress advances from 0.0 to 1.0.
  6. Final Completion — Use success, average transfer speed, and error from the completion handler.

Prerequisites

  • The device is connected and conforms to DeviceOtaAPI.
  • Device battery is at least otaBatteryLimit percent.
  • filePath points to the correct, complete firmware package for this device.
  • Keep the app active and connection stable until completion.

API Reference

Framework

AIBuds.xcframework

Import

Swift

import AIBuds
import AIBudsFoundation

Objective-C

#import <AIBuds/AIBuds-Swift.h>
#import <AIBuds/AIBuds.h>

Protocol

Swift

/// The protocol for device OTA upgrade API.
protocol DeviceOtaAPI: DeviceAPI {
    /// OTA battery limit, 0...100, unit: percent.
    var otaBatteryLimit: Int { get }

    /// Start OTA upgrade.
    /// - Parameters:
    ///   - filePath: Upgrade file path.
    ///   - startHandler: Upgrade start callback.
    ///     - success: Whether the OTA task started successfully.
    ///     - error: Failure information, or `nil` if the task started.
    ///   - progressHandler: Upgrade progress callback.
    ///     - progress: Progress value in the range `0.0...1.0`.
    ///   - completionHandler: Final upgrade completion callback.
    ///     - success: Whether the upgrade succeeded.
    ///     - avgSpeed: Average transfer speed in kB/s.
    ///     - error: Failure information, or `nil` if the upgrade succeeded.
    func startOta(
        withFilePath filePath: String,
        startHandler: AIBudsOtaStartCompletionHandler?,
        progressHandler: AIBudsOtaProgressHandler?,
        completionHandler: AIBudsOtaCompletionHandler?
    )

    /// Start OTA upgrade with an explicit transfer protocol configuration.
    /// - Parameters:
    ///   - filePath: Upgrade file path.
    ///   - configuration: OTA protocol configuration.
    ///   - startHandler: Upgrade start callback.
    ///     - success: Whether the OTA task started successfully.
    ///     - error: Failure information, or `nil` if the task started.
    ///   - progressHandler: Upgrade progress callback.
    ///     - progress: Progress value in the range `0.0...1.0`.
    ///   - completionHandler: Final upgrade completion callback.
    ///     - success: Whether the upgrade succeeded.
    ///     - avgSpeed: Average transfer speed in kB/s.
    ///     - error: Failure information, or `nil` if the upgrade succeeded.
    func startOta(
        withFilePath filePath: String,
        configuration: OtaConfiguration,
        startHandler: AIBudsOtaStartCompletionHandler?,
        progressHandler: AIBudsOtaProgressHandler?,
        completionHandler: AIBudsOtaCompletionHandler?
    )
}

Objective-C

/// The protocol for device OTA upgrade API.
@protocol AIBudsDeviceOtaAPI <AIBudsDeviceAPI>
/// OTA battery limit, 0...100, unit: percent.
@property(nonatomic, readonly) NSInteger otaBatteryLimit;

/// Start OTA upgrade from a local firmware path.
///
/// - Parameters:
///   - filePath: The readable local firmware file path.
///   - startHandler: Called when the OTA start attempt completes.
///     - success: `YES` if the OTA task started; otherwise `NO`.
///     - error: Failure information, or `nil` if the task started.
///   - progressHandler: Called when OTA progress changes.
///     - progress: Progress in the range `0.0...1.0`.
///   - completionHandler: Called when the OTA operation finishes.
///     - success: `YES` if the upgrade succeeded; otherwise `NO`.
///     - avgSpeed: Average transfer speed in kB/s.
///     - error: Failure information, or `nil` if the upgrade succeeded.
- (void)startOtaWithFilePath:(NSString *_Nonnull)filePath
                startHandler:(AIBudsOtaStartCompletionHandler _Nullable)startHandler
             progressHandler:(AIBudsOtaProgressHandler _Nullable)progressHandler
           completionHandler:(AIBudsOtaCompletionHandler _Nullable)completionHandler;

/// Start OTA upgrade with an explicit transfer protocol configuration.
///
/// - Parameters:
///   - filePath: The readable local firmware file path.
///   - configuration: The OTA protocol configuration required by the device.
///   - startHandler: Called when the OTA start attempt completes.
///     - success: `YES` if the OTA task started; otherwise `NO`.
///     - error: Failure information, or `nil` if the task started.
///   - progressHandler: Called when OTA progress changes.
///     - progress: Progress in the range `0.0...1.0`.
///   - completionHandler: Called when the OTA operation finishes.
///     - success: `YES` if the upgrade succeeded; otherwise `NO`.
///     - avgSpeed: Average transfer speed in kB/s.
///     - error: Failure information, or `nil` if the upgrade succeeded.
- (void)startOtaWithFilePath:(NSString *_Nonnull)filePath
               configuration:(AIBudsOtaConfiguration *_Nonnull)configuration
                startHandler:(AIBudsOtaStartCompletionHandler _Nullable)startHandler
             progressHandler:(AIBudsOtaProgressHandler _Nullable)progressHandler
           completionHandler:(AIBudsOtaCompletionHandler _Nullable)completionHandler;
@end

See otaBatteryLimit and the startOta overloads in the API Reference.

OTA Configuration

OtaConfiguration selects the BLE OTA protocol used by the configured overload. Its otaProtocol property defaults to .abmate.

Swift Objective-C Raw value Meaning
.abmate AIBudsOtaProtocolKindAbmate 0 ABMate OTA protocol.
.fitcloudPro AIBudsOtaProtocolKindFitcloudPro 1 FitCloud Pro OTA protocol.

Do not select a protocol by guessing from the firmware file. Use the protocol required by the connected device and product integration.

Return Value

Neither overload returns a value directly. startHandler reports whether the OTA task started, progressHandler reports normalized progress, and completionHandler provides the authoritative final result and average transfer speed.

Usage Examples

Swift

guard let device = device as? DeviceOtaAPI else { return }
guard deviceBatteryPercent >= device.otaBatteryLimit else {
    print("Charge the device before updating")
    return
}

device.startOta(
    withFilePath: firmwareURL.path,
    startHandler: { success, error in
        if !success { print(error?.localizedDescription ?? "OTA failed to start") }
    },
    progressHandler: { progress in
        print("OTA: \(Int(progress * 100))%")
    },
    completionHandler: { success, averageSpeed, error in
        print(
            success
                ? "OTA completed at \(averageSpeed) kB/s"
                : (error?.localizedDescription ?? "OTA failed"))
    })

Objective-C

id<AIBudsDeviceOtaAPI> device = (id<AIBudsDeviceOtaAPI>)self.device;
if (![device conformsToProtocol:@protocol(AIBudsDeviceOtaAPI)])
    return;

[device startOtaWithFilePath:firmwareURL.path
    startHandler:^(BOOL success, NSError *_Nullable error) {
        if (!success)
            NSLog(@"OTA failed to start: %@", error.localizedDescription);
    }
    progressHandler:^(CGFloat progress) {
        NSLog(@"OTA: %.0f%%", progress * 100);
    }
    completionHandler:^(BOOL success, CGFloat averageSpeed, NSError *_Nullable error) {
        if (success) {
            NSLog(@"OTA completed at %.2f kB/s", averageSpeed);
        } else {
            NSLog(@"OTA failed: %@", error.localizedDescription);
        }
    }];

Use an Explicit OTA Protocol

Use the configured overload only when your product integration knows which OTA protocol the connected device requires.

Swift

let configuration = OtaConfiguration()
configuration.otaProtocol = .fitcloudPro

device.startOta(
    withFilePath: firmwareURL.path,
    configuration: configuration,
    startHandler: { success, error in
        if !success {
            print(error?.localizedDescription ?? "OTA failed to start")
        }
    },
    progressHandler: { progress in
        print("OTA: \(Int(progress * 100))%")
    },
    completionHandler: { success, averageSpeed, error in
        print(
            success
                ? "OTA completed at \(averageSpeed) kB/s"
                : (error?.localizedDescription ?? "OTA failed"))
    }
)

Objective-C

AIBudsOtaConfiguration *configuration = [[AIBudsOtaConfiguration alloc] init];
configuration.otaProtocol = AIBudsOtaProtocolKindFitcloudPro;

[device startOtaWithFilePath:firmwareURL.path
    configuration:configuration
    startHandler:^(BOOL success, NSError *_Nullable error) {
        if (!success)
            NSLog(@"OTA failed to start: %@", error.localizedDescription);
    }
    progressHandler:^(CGFloat progress) {
        NSLog(@"OTA: %.0f%%", progress * 100);
    }
    completionHandler:^(BOOL success, CGFloat averageSpeed, NSError *_Nullable error) {
        if (success) {
            NSLog(@"OTA completed at %.2f kB/s", averageSpeed);
        } else {
            NSLog(@"OTA failed: %@", error.localizedDescription);
        }
    }];

Error Handling

OTA errors use AIBudsSDK.OtaErrorDomain and SdkOtaErrorCode.

Codes Typical condition
unknown The SDK cannot classify the error more narrowly.
otaTaskAlreadyRunning Another OTA task is already active.
otaTaskCreateFailedDueToFileNotFound The local firmware path does not exist.
otaTaskStartFailedDueToFileReadError, otaTaskStartFailedDueToFileHandleCreateError The package cannot be opened or read.
otaTaskStartFailedDueToInvalidFileHashData Firmware hash data is invalid.
otaTaskStartFailedDueToGetOtaInfoError Required OTA metadata cannot be obtained.
otaTaskStartFailedDueToInvalidOffsetAddress, otaTaskStartFailedDueToInvalidBlockSize Transfer metadata is invalid.
otaTaskStartFailedDueToNotAllowUpdate The device does not allow the update in its current state.
otaTaskSendDataFailedDueToFileHandleIsNil, otaTaskSendDataFailedDueToSeekFileHandleFailed, otaTaskSendDataFailedDueToReadFileDataFailed, otaTaskSendDataFailedDueToOtaInfoIsNil The SDK cannot continue reading or sending firmware data.
otaTaskFailedDueToDeviceReportKeyMismatch, otaTaskFailedDueToDeviceReportCrcError, otaTaskFailedDueToDeviceReportSeqError, otaTaskFailedDueToDeviceReportDataLengthError The device rejects transferred data or reports an integrity/sequence problem.
otaTaskFailedDueToDeviceDisconnect, otaTaskFailedDueToTimeout The device disconnects or the operation times out.

Distinguish startHandler failure from a failure after transfer begins. Do not retry automatically with an unverified package; revalidate device model, firmware version, package integrity, battery, protocol selection, and connection first.

Best Practices

  1. Complete update discovery, download, signature or integrity verification, and device-model compatibility checks before calling the SDK.
  2. Check otaBatteryLimit immediately before starting, not only when presenting the update UI.
  3. Prevent concurrent OTA, Camera OTA, Media File Import, or other long-running device operations.
  4. Dispatch UI updates to the main queue because callbacks may arrive on another queue.
  5. Treat startHandler as task-start confirmation only; do not report upgrade success until completionHandler succeeds.
  6. Keep the app active and the device connection stable through final completion, then verify the reported firmware version after reconnecting.

Notes

  • Progress is normalized to 0.0...1.0; clamp UI presentation defensively without changing the SDK result.
  • avgSpeed is reported in kB/s only by the final completion handler.
  • OtaConfiguration.otaProtocol defaults to .abmate; choose .fitcloudPro only for devices that require it.
  • The SDK does not expose an OTA cancellation method. The Demo's Cancel button resets its local UI state and must not be documented as cancelling the SDK operation.

AIBuds SDK iOS Wiki

Clone this wiki locally