/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ import { AsyncObservable, Bytes, CancelablePromise, Duration, MaybePromise, Timer } from "@matter/general"; import { OtaImageHeader, PersistedFileDesignator } from "@matter/protocol"; import { OtaSoftwareUpdateProvider } from "@matter/types/clusters/ota-software-update-provider"; import { OtaSoftwareUpdateRequestor } from "@matter/types/clusters/ota-software-update-requestor"; import { OtaSoftwareUpdateRequestorBehavior } from "./OtaSoftwareUpdateRequestorBehavior.js"; export interface ProviderLocation extends OtaSoftwareUpdateRequestor.ProviderLocation { } export interface ActiveProviderLocation { location: ProviderLocation; previousQueryTimestamp: number | null; metadataForNode?: Bytes; } export interface UpdateInProgressDetails { newSoftwareVersion: number; location?: ProviderLocation; updateToken?: Bytes; } /** * This is the default server implementation of {@link OtaSoftwareUpdateRequestorBehavior}. * * To use OTA updates for matter.js based devices, you need to implement "applying the update" yourself! * The default implementation provides anything needed to check for updates and transfer new updates, according to the * Matter specification, but applying the update is too specific to your use case and the environment where the device * is used. * * The following custom state attributes are available to configure the behavior of the cluster: * * {@link updateQueryInterval}: Interval to check for updates, default: 24h as defined in Matter specification * * * {@link transferProtocolsSupported}: List of Transfer protocols that are announced as supported. By default, we only * export BDX; we also support HTTPS (but basically no one else) * * * {@link canConsent}: Can the node request consent from the user for the update itself? Default is set to true, and the * controller needs to take care to get the necessary consent when calling {@link requestUserConsent}. * * * {@link downloadLocation}: Option to provide a custom storage location (also backed by an own Storage solution) to store * the received update file in. If not provided, a default location is used. * * * For this the following extension points exist that need to be implemented: * * {@link requestUserConsent}: This method is needed to be implemented when you set {@link canConsent} to true and needs to * implement user consent gathering. * * * {@link applyUpdate}: The method is called with the new SoftwareVersion and the PersistedFileDescriptor where a downloaded * update is placed and needs to trigger the update process including shutdown and restart of the node and also * sending "bootReason" event after the update! It runs in its own transaction after the record of the update is * stored. If the update fails, or the node keeps running the old version, it deletes the downloaded file: a file * left behind is applied again at the next query without asking the provider, so no `NotifyUpdateApplied` * follows. After a restart into the new version the requestor discards the file itself. If it throws, the * requestor logs the error, forgets the update and returns to idle. * * * {@link validateUpdateFile}: This method in default implementation reads the received OTA file and validates header and * checksums and basic details. Override this method and use this.getDownloadLocation() for access if any custom * validations are needed */ export declare class OtaSoftwareUpdateRequestorServer extends OtaSoftwareUpdateRequestorBehavior { #private; protected internal: OtaSoftwareUpdateRequestorServer.Internal; readonly state: OtaSoftwareUpdateRequestorServer.State; readonly events: OtaSoftwareUpdateRequestorServer.Events; static readonly schema: import("@matter/model").ClusterModel; initialize(): Promise; getDownloadLocation(): Promise; /** * Default implementation for the announceOtaProvider command. * A Node announced itself as OTA Update Provider, so schedule an update check with it. * Depending on the announcementReason, we schedule the update query earlier with this provider or wait for the * next regular check. */ announceOtaProvider({ providerNodeId, vendorId, announcementReason, metadataForNode, endpoint, }: OtaSoftwareUpdateRequestor.AnnounceOtaProviderRequest): Promise; /** * Validate the update file * The default implementation does basic validations based on the matter OTA file format and expected software * version. * The method SHALL be overridden to add additional checks like validating the signature of the file. * throws an error if the file is invalid */ protected validateUpdateFile(newSoftwareVersion?: number): Promise; protected applyUpdate(_newSoftwareVersion: number, _fileDesignator: PersistedFileDesignator): MaybePromise; protected requestUserConsent(_newSoftwareVersion: number, _newSoftwareVersionString: string): MaybePromise; [Symbol.asyncDispose](): Promise; } export declare namespace OtaSoftwareUpdateRequestorServer { class State extends OtaSoftwareUpdateRequestorBehavior.State { /** * How long to wait before querying a provider that announced an update other than a simple one. * * Unset draws the specified random window, so that the nodes of a fabric announced to together do * not query at once. A node that knows it is alone with its provider may name a shorter wait; the * specification states a preference rather than a requirement, so a fixed value still conforms. * * @see {@link MatterSpecification.v161.Core} § 11.20.7.4.1.3 */ announcedUpdateQueryDelay?: Duration; /** * Shortest interval this requestor leaves between two `QueryImage` commands to one provider, * which also floors the `DelayedActionTime` a `Busy` answer names. * * The specification requires two minutes, which is the default. It is settable so a test * harness can observe the exchange that follows a delayed answer without waiting the delay * out; a product that lowers it does not conform. * * @see {@link MatterSpecification.v161.Core} § 11.20.3.2 */ minimumQueryInterval: Duration; /** * Shortest interval this requestor leaves before re-sending an `ApplyUpdateRequest` a provider * answered `AwaitNextAction`, which also floors the `DelayedActionTime` that answer names. * * As {@link minimumQueryInterval}: the specification requires two minutes, and lowering it is * for a harness rather than for a product. * * @see {@link MatterSpecification.v161.Core} § 11.20.3.6 */ minimumApplyDelay: Duration; /** * The list of OTA providers that were recently active (by announcement or by being used). * A provider that supports none of this requestor's download protocols is removed from this list and from the * default providers; one that fails or has no update is tried after the others next time. * This value is persisted. */ activeOtaProviders: ActiveProviderLocation[]; /** * Details of an upgrade in progress, set when the update is applied and consumed on the next start: if the node * then runs {@link UpdateInProgressDetails.newSoftwareVersion} it emits `VersionApplied` and, where the update * came from a provider with a token, reports it applied to that provider; otherwise it reports a failure and * queries again. A failing `applyUpdate` clears it. This value is persisted. */ updateInProgressDetails: UpdateInProgressDetails | null; /** How often to query for updates. Default is 24 hours ("daily") as proposed by spec. */ updateQueryInterval: Duration; /** * The transfer protocols supported by this requestor. Default is BDX Synchronous. * If it was verified that the node really have access to the public internet, HTTPS can be added as protocol * as well. */ transferProtocolsSupported: OtaSoftwareUpdateProvider.DownloadProtocol[]; /** * If true the requestor is able to get user consent for an update. This requires the implementation of the * requestUserConsent() extension interface method. * If false the OTA provider will only provide updates that do not require user consent or where user consent * was already given. * Default is false. */ canConsent: boolean; /** * Optional custom persisted location as PersistedFileDescriptor to store the downloaded update files. * If not provided, the default storage context for "bdx" of the node is used with a filename like * "ota-{vendorId}-{productId}.update". * This can be used to store the files in a different persistent storage if needed. */ downloadLocation?: PersistedFileDesignator; } class Events extends OtaSoftwareUpdateRequestorBehavior.Events { /** Emitted when a new software update file was downloaded and should now be applied. */ updateReadyToApply: AsyncObservable; } class Internal { /** Timer for the next update query */ updateQueryTimer: Timer | undefined; /** Whether an update query runs, including its download and the delays the provider requests */ queryRunning: boolean; /** * The preferred provider to use for the next update query. * Mainly used for the Busy case to reuse the same provider for the next try. */ selectedProviderLocation?: ProviderLocation; /** How often we already retried to connect to the current provider */ providerRetryCount: number; /** * Stores the time of a current update delay to allow cancelling it */ updateDelayPromise: CancelablePromise | undefined; /** * Persisted location as PersistedFileDescriptor to store the downloaded update files. * It is initialized from the state or with an internal default on startup. */ downloadLocation: PersistedFileDesignator; /** Reports download progress in a dedicated transaction */ updateProgress: (bytesDownloaded: number, totalBytes?: number) => void; /** Applies a prepared update in a dedicated transaction */ applyPreparedUpdate?: (newSoftwareVersion: number, fileDesignator: PersistedFileDesignator) => void; } const ExtensionInterface: { requestUserConsent(newSoftwareVersion: number, newSoftwareVersionString: string): MaybePromise; applyUpdate(newSoftwareVersion: number, fileDesignator: PersistedFileDesignator): MaybePromise; validateUpdateFile(newSoftwareVersion?: number): MaybePromise; }; } //# sourceMappingURL=OtaSoftwareUpdateRequestorServer.d.ts.map