/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ import { Agent } from "#endpoint/Agent.js"; import { Endpoint } from "#endpoint/Endpoint.js"; import { AsyncObservable, Duration, MaybePromise, Timestamp } from "@matter/general"; import { Behavior } from "./Behavior.js"; import { BehaviorBacking } from "./internal/BehaviorBacking.js"; /** * Attribute transition management. * * This utility supports updates of one or more attributes of a single behavior when the change occurs gradually over * time. * * The nuances of integrating Matter transition semantics with a device can be complicated. Matter specifies the * frequency of updates for levels and "remaining time" attributes. These semantics may not map well to your device. * * This class attempts to offer implementors significant flexibility. To that end, we offer several integration * approaches: * * 1. If you instantiate with {@link Transitions.Configuration.manageTransitions} as false, no transition occurs and * device state updates instantly. * * 2. If you enable transition management but provide no other options, matter.js will perform transitions for you, * updating values using a timer. You probably do not want to use this option if your device supports transitions * natively. * * 3. If you implement transitions in hardware or a bridged device, you can still use matter.js to track ongoing * transitions and report remaining time. To do this, extend this class and implement {@link transitionImmediately} * and {@link transitionGradually}. matter.js will report changes as you update local state and report transition * completion when all attributes reach their target value or when you invoke {@link finish}. * * 4. You can also allow matter.js to operate a transition timer but apply value updates directly to hardware by * overriding {@link applyUpdates} (and use `determineUpdates()` if needed) or {@link step}. This is useful if your * device does not support transitions natively, but you want to ensure that matter.js does not report values that * do not reflect hardware state. * * Whichever approach you take, matter.js attempts to implement the Matter protocol as accurately as possible with the * information available. */ export declare class Transitions { #private; constructor(endpoint: Endpoint, config: Transitions.Configuration); /** * Iterate over all active transitions. */ [Symbol.iterator](): ArrayIterator>; /** * Get iteration state for a specific property. */ stateOf(name: Transitions.PropertyOf): Transitions.PropertyState | undefined; /** * Calculate the distance between two values in a cyclic range. This is the default implementation only caring * about normal upwards and downwards transitions. */ protected calculateCyclicDistance(currentValue: number, targetValue: number, changePerS: number, min: number, max: number): number; /** * Initiate transition of an attribute. */ start(transition: Transitions.Transition): MaybePromise; /** * Immediately change to a target value. * * The default implementation updates the local state value and calls `applyUpdates()`. */ protected transitionImmediately(owner: B, name: Transitions.PropertyOf, targetValue: number): MaybePromise; /** * Initiate gradual transition to a target value. * * The default implementation starts a timer to drive transitions over time. */ protected transitionGradually(_attr: Transitions.PropertyState): void; /** * Stop transition of one or all attributes. */ stop(name?: Transitions.PropertyOf): void; /** * Stop a transition of one or more attributes that has completed successfully. */ finish(name?: Transitions.PropertyOf): void; /** * Free resources. */ close(): Promise; /** * Set the static version of remaining time used when transition management is disabled. */ set remainingTime(value: number); /** * Determine time remaining in transition in (possibly fractional) seconds. * * This is computed dynamically based on the longest running individual attribute transition. */ get remainingTime(): number; /** * Update transitioning attributes for a behavior. * * You may override this method if you want matter.js to run a timer, but you want to handle value updates yourself. */ protected step(behavior: B): Promise; /** Determine the changes to be applied to the behavior and return as key-value object. */ protected determineUpdates(behavior: B): Partial>; /** * This method is called to apply the changes to the behavior. * The default implementation detects the changed attributes using the method `determineChanges()`and updates the * state of the behavior. It also returns them as an key-value object, which can be useful when just requiring the * changes values in an extended class. */ protected applyUpdates(behavior: B, changes: Partial>): MaybePromise>>; } export declare namespace Transitions { const DEFAULT_STEP_INTERVAL: Duration; const DEFAULT_EXTERNAL_TIME_UNIT: Duration; /** * A valid transitionable attribute name for the specified type. */ type AttrOf = keyof { [K in keyof InstanceType["state"]]: T[K] extends number | undefined | null ? true : never; }; /** * Transition configuration. * * The {@link Transitions} accesses this configuration on-demand so values that change after initial construction * will affect ongoing behavior. */ interface Configuration { /** * The behavior type this configuration applies to. */ readonly type: Behavior.Type & { new (agent: Agent, backing: BehaviorBacking): B; }; /** * If this is false we do not manage transitions and "remaining time" behaves like a normal static value. * * Default is true. */ readonly manageTransitions?: boolean; /** * Interval per external time unit. Defaults to 100ms which is appropriate for CC & LVL "remaining time" * attribute that is defined as 10ths of a second. */ readonly externalTimeUnit?: Duration; /** * The internal tick rate for transitions. * * This is the smallest time increment between value adjustments. * * Defaults to {@link DEFAULT_STEP_INTERVAL}. */ readonly stepInterval?: Duration; /** * The end time for a transition if transition management is disabled. */ readonly transitionEndTimeMs?: number; /** * An observable associated with the "remaining time" value. * * If present, the {@link Transitions} forces an emit under conditions defined in spec for the "RemainingTime" * attribute of Level Control & Color Control clusters. * * This should also support Valve Configuration & Control cluster's "RemainingDuration" attribute with * additional options to support small variations in logic. */ readonly remainingTimeEvent?: AsyncObservable<[oldValue: number, newValue: number, context: undefined]>; /** * The state properties that support transition. */ readonly properties: Partial, PropertyConfiguration>>; } /** * Configures a state property to support transitions. This is typically an attribute but we support transition of * any numeric property. */ interface PropertyConfiguration { /** * A lower bound on the transition value. */ readonly min?: number | undefined; /** * An upper bound on the transition value. */ readonly max?: number | undefined; /** * Is the property transitioning ina cyclic manner? means it overflows to the min value when it reaches the max */ cyclic?: boolean; } type StateOf = { [N in string & keyof B["state"]]: B[N] extends number | null | undefined ? true : never; }; type PropertyOf = keyof StateOf; /** * Configuration for transition of a specific attribute. */ interface Transition { /** * The attribute to transition. */ readonly name: PropertyOf; /** * The behavior instance requesting transition. */ readonly owner: B; /** * The amount to change the attribute per second. */ readonly changePerS?: number | null; /** * The target value for the transition. * * If the property is not transitioning "cyclic" the following rules apply: * * * If undefined, transitions to the min/max value. * * * If no min or max is defined and no target value is supplied the transition will not run. * * If the property is transitioning "cyclic" the following rules apply: * * * If undefined, the transition will be endless and needs to be stopped manually. * * * If a target value is defined, the transition logic calculates the distance to the target value and stops * on the target value once this distance was processed. By default, the distance is calculated linearly, but * this behavior can be overridden with the custom function below. */ readonly targetValue?: number; /** * A function to calculate the distance between the current value and the target value. */ calculateCyclicDistance?: (currentValue: number, targetValue: number) => number; /** * Invoked every time the transitioning value changes before committing the mutating transaction. */ onStep?: (this: B, value: number) => MaybePromise; } /** * Internal state related to actively transitioning attributes. */ interface PropertyState { /** * The property name. */ name: PropertyOf; /** * Configuration for any active transition. */ configuration: Transition; /** * The current value for the transition. * * We track separately from canonical value because we transition using floats but values are typically * integers. This allows us to avoid rounding errors. */ currentValue: number; /** * The change in value per millisecond. */ changePerMs: number; /** * The distance left in the transition for cyclic properties. */ distanceLeft?: number; /** * The time of the last step. */ prevStepAt: Timestamp; /** * Set to true when the reporting of remaining time should be suppressed when finishing the transition. * This usually is used for transitions that are faster than 1s. */ suppressReportingRemainingTimeOnFinish?: boolean; } } //# sourceMappingURL=Transitions.d.ts.map