@hangtime/grip-connect
Version:
Griptonite Motherboard, Tindeq Progressor, PitchSix Force Board, WHC-06, Entralpi, Climbro, mySmartBoard: Bluetooth API Force-Sensing strength analysis for climbers
543 lines • 20.7 kB
TypeScript
import { BaseModel } from "./../models/base.model.js";
import type { IDevice, Service } from "../interfaces/device.interface.js";
import type { ActiveCallback, ForceMeasurement, ForceUnit, NotifyCallback, WriteCallback } from "../interfaces/callback.interface.js";
import type { DownloadPacket } from "../interfaces/download.interface.js";
import type { Commands } from "../interfaces/command.interface.js";
export declare abstract class Device extends BaseModel implements IDevice {
/**
* Filters to identify the device during Bluetooth scanning.
* Used to match devices that meet specific criteria such as name, service UUIDs, etc.
* @type {BluetoothLEScanFilter[]}
* @public
* @readonly
*/
readonly filters: BluetoothLEScanFilter[];
/**
* Array of services provided by the device.
* Services represent functionalities that the device supports, such as weight measurement, battery information, or custom services.
* @type {Service[]}
* @public
* @readonly
*/
readonly services: Service[];
/**
* Reference to the `BluetoothDevice` object representing this device.
* This is the actual device object obtained from the Web Bluetooth API after a successful connection.
* @type {BluetoothDevice | undefined}
* @public
*/
bluetooth?: BluetoothDevice;
/**
* Object representing the set of commands available for this device.
* These commands allow communication with the device to perform various operations such as starting measurements, retrieving data, or calibrating the device.
* @type {Commands}
* @public
* @readonly
*/
readonly commands: Commands;
/**
* The BluetoothRemoteGATTServer interface of the Web Bluetooth API represents a GATT Server on a remote device.
* @type {BluetoothRemoteGATTServer | undefined}
* @private
*/
private server;
/**
* The last message written to the device.
* @type {string | Uint8Array | null}
* @protected
*/
protected writeLast: string | Uint8Array | null;
/**
* Indicates whether the device is currently active.
* @type {boolean}
*/
protected isActive: boolean;
/**
* Configuration for threshold and duration.
*/
private activeConfig;
/**
* Highest instantaneous force (peak) recorded in the session; may be negative.
* Initialized to Number.NEGATIVE_INFINITY so the first sample sets the peak.
* @type {number}
* @protected
*/
protected peak: number;
/**
* Mean (average) force over the session, initialized to 0.
* @type {number}
* @protected
*/
protected mean: number;
/**
* Lowest instantaneous force recorded in the session; may be negative.
* Initialized to Number.POSITIVE_INFINITY so the first sample sets the min.
* @type {number}
* @protected
*/
protected min: number;
/**
* Display unit for force measurements (output unit for notify callbacks).
* @type {ForceUnit}
* @protected
*/
protected unit: ForceUnit;
/**
* Unit of the values streamed by the device (kg for most devices, lbs for ForceBoard).
* @type {ForceUnit}
* @protected
*/
protected streamUnit: ForceUnit;
/**
* Optional sampling rate in Hz when known or calculated from notification timestamps.
* @type {number | undefined}
* @protected
*/
protected samplingRateHz?: number;
/**
* Timestamp (ms) of the previous BLE notification for notify-interval calculation.
* @protected
*/
protected lastPacketTimestamp: number;
/**
* Count of data packets received this session (one BLE notification = one packet).
* @protected
*/
protected packetCount: number;
/**
* Notify interval in ms for the current packet (set by recordPacketReceived).
* @protected
*/
protected currentNotifyIntervalMs: number | undefined;
/**
* Samples in the current packet (set by device before buildForceMeasurement).
* @protected
*/
protected currentSamplesPerPacket: number | undefined;
/**
* Call at the start of each BLE notification (packet). Updates notify interval and packet count.
* @protected
*/
protected recordPacketReceived(): void;
/**
* Reset packet tracking (call when starting a new stream).
* @protected
*/
protected resetPacketTracking(): void;
/**
* Start time of the current rate measurement interval.
* @type {number}
* @private
*/
private rateIntervalStart;
/**
* Number of samples in the current rate measurement interval.
* @type {number}
* @private
*/
private rateIntervalSamples;
/**
* Running sum of force values for the session.
* Used to calculate mean (average) force.
* @type {number}
* @protected
*/
protected sum: number;
/**
* Number of data points received from the device.
* Used to calculate the average mass.
* @type {number}
* @protected
*/
protected dataPointCount: number;
/**
* Array of DownloadPacket entries.
* This array holds packets that contain data downloaded from the device.
* @type {DownloadPacket[]}
* @protected
*/
protected downloadPackets: DownloadPacket[];
/**
* Represents the current tare value for calibration.
* @type {number}
*/
private tareCurrent;
/**
* Indicates whether the tare calibration process is active.
* @type {boolean}
*/
private tareActive;
/**
* Timestamp when the tare calibration process started.
* @type {number | null}
*/
private tareStartTime;
/**
* Array holding the samples collected during tare calibration.
* @type {number[]}
*/
private tareSamples;
/**
* Duration time for the tare calibration process.
* @type {number}
*/
private tareDuration;
/**
* Optional callback for handling mass/force data notifications.
* @callback NotifyCallback
* @param {ForceMeasurement} data - The force measurement passed to the callback.
* @type {NotifyCallback | undefined}
* @protected
*/
protected notifyCallback: NotifyCallback;
/**
* Optional callback for handling write operations.
* @callback WriteCallback
* @param {string} data - The data passed to the callback.
* @type {WriteCallback | undefined}
* @protected
*/
protected writeCallback: WriteCallback;
/**
* Optional callback for handling write operations.
* @callback ActiveCallback
* @param {string} data - The data passed to the callback.
* @type {ActiveCallback | undefined}
* @protected
*/
protected activeCallback: ActiveCallback;
/**
* Event listener for handling the 'gattserverdisconnected' event.
* This listener delegates the event to the `onDisconnected` method.
*
* @private
* @type {(event: Event) => void}
*/
private onDisconnectedListener;
/**
* A map that stores notification event listeners keyed by characteristic UUIDs.
* This allows for proper addition and removal of event listeners associated with each characteristic.
*
* @private
* @type {Map<string, EventListener>}
*/
private notificationListeners;
constructor(device: Partial<IDevice>);
/**
* Builds a ForceMeasurement for a single zone (e.g. left/center/right).
* With one argument, current/peak/mean are all set to that value.
* With three arguments, uses the given current, peak, and mean for the zone.
* @param valueOrCurrent - Force value, or current force for this zone
* @param peak - Optional peak for this zone (required if mean is provided)
* @param mean - Optional mean for this zone
* @returns ForceMeasurement (no nested distribution)
* @protected
*/
protected buildZoneMeasurement(valueOrCurrent: number, peak?: number, mean?: number): ForceMeasurement;
/**
* Interval duration (ms) for sampling rate calculation.
* @private
* @readonly
*/
private static readonly RATE_INTERVAL_MS;
/**
* Calculates sampling rate: samples per second.
* Uses fixed intervals to avoid sliding window edge effects.
* @private
*/
private updateSamplingRate;
/**
* Shared base for ForceMeasurement/DownloadPacket payload construction.
* @private
*/
private buildForcePayload;
/**
* Builds a ForceMeasurement payload for notify callbacks.
* @param current - Current force at this sample
* @param distribution - Optional per-zone measurements (e.g. from buildZoneMeasurement)
* @returns ForceMeasurement
* @protected
*/
protected buildForceMeasurement(current: number, distribution?: {
left?: ForceMeasurement;
center?: ForceMeasurement;
right?: ForceMeasurement;
}): ForceMeasurement;
/**
* Builds a DownloadPacket for export (CSV, JSON, XML).
* Converts force values from streamUnit to display unit.
* @param current - Current force at this sample (stream unit)
* @param samples - Raw sensor/ADC values from device
* @param options - Optional timestamp, battRaw, sampleIndex, distribution (for multi-zone)
* @returns DownloadPacket
* @protected
*/
protected buildDownloadPacket(current: number, samples: number[], options?: {
timestamp?: number;
battRaw?: number;
sampleIndex?: number;
distribution?: {
left?: ForceMeasurement;
center?: ForceMeasurement;
right?: ForceMeasurement;
};
}): DownloadPacket;
/**
* Sets the callback function to be called when the activity status changes,
* and optionally sets the configuration for threshold and duration.
*
* This function allows you to specify a callback that will be invoked whenever
* the activity status changes, indicating whether the device is currently active.
* It also allows optionally configuring the threshold and duration used to determine activity.
*
* @param {ActiveCallback} callback - The callback function to be set. This function
* receives a boolean value indicating the new activity status.
* @param {object} [options] - Optional configuration object containing the threshold and duration.
* @param {number} [options.threshold=2.5] - The threshold value for determining activity.
* @param {number} [options.duration=1000] - The duration (in milliseconds) to monitor the input for activity.
* @returns {void}
* @public
*
* @example
* device.active((isActive) => {
* console.log(`Device is ${isActive ? 'active' : 'inactive'}`);
* }, { threshold: 3.0, duration: 1500 });
*/
active: (callback: ActiveCallback, options?: {
threshold?: number;
duration?: number;
}) => void;
/**
* Checks if a dynamic value is active based on a threshold and duration.
*
* This function assesses whether a given dynamic value surpasses a specified threshold
* and remains active for a specified duration. If the activity status changes from
* the previous state, the callback function is called with the updated activity status.
*
* @param {number} input - The dynamic value to check for activity status.
* @returns {Promise<void>} A promise that resolves once the activity check is complete.
*
* @example
* await device.activityCheck(5.0);
*/
protected activityCheck: (input: number) => Promise<void>;
/**
* Connects to a Bluetooth device.
* @param {Function} [onSuccess] - Optional callback function to execute on successful connection. Default logs success.
* @param {Function} [onError] - Optional callback function to execute on error. Default logs the error.
* @public
*
* @example
* device.connect(
* () => console.log("Connected successfully"),
* (error) => console.error("Connection failed:", error)
* );
*/
connect: (onSuccess?: () => void, onError?: (error: Error) => void) => Promise<void>;
/**
* Disconnects the device if it is currently connected.
* - Removes all notification listeners from the device's characteristics.
* - Removes the 'gattserverdisconnected' event listener.
* - Attempts to gracefully disconnect the device's GATT server.
* - Resets relevant properties to their initial states.
* @returns {void}
* @public
*
* @example
* device.disconnect();
*/
disconnect: () => void;
/**
* Converts the `downloadPackets` array into a CSV formatted string.
* @returns {string} A CSV string representation of the `downloadPackets` data, with each packet on a new line.
* @private
*
* @example
* const csvData = device.downloadToCSV();
* console.log(csvData);
*/
protected downloadToCSV: () => string;
/**
* Converts an array of DownloadPacket objects to a JSON string.
* @returns {string} JSON string representation of the data.
* @private
*
* @example
* const jsonData = device.downloadToJSON();
* console.log(jsonData);
*/
protected downloadToJSON: () => string;
/**
* Converts an array of DownloadPacket objects to an XML string.
* @returns {string} XML string representation of the data.
* @private
*
* @example
* const xmlData = device.downloadToXML();
* console.log(xmlData);
*/
protected downloadToXML: () => string;
/**
* Exports the data in the specified format (CSV, JSON, XML) with a filename format:
* 'data-export-YYYY-MM-DD-HH-MM-SS.{format}'.
*
* @param {('csv' | 'json' | 'xml')} [format='csv'] - The format in which to download the data.
* Defaults to 'csv'. Accepted values are 'csv', 'json', and 'xml'.
*
* @returns {Promise<void>} Resolves when the data has been downloaded/written
* @public
*
* @example
* await device.download('json');
*/
download: (format?: "csv" | "json" | "xml") => Promise<void>;
/**
* Returns UUIDs of all services associated with the device.
* @returns {string[]} Array of service UUIDs.
* @protected
*
* @example
* const serviceUUIDs = device.getAllServiceUUIDs();
* console.log(serviceUUIDs);
*/
protected getAllServiceUUIDs: () => string[];
/**
* Returns the Bluetooth instance available for the current environment.
* In browsers, it returns the native Web Bluetooth API (i.e. `navigator.bluetooth`).
* In a Node, Bun, or Deno environment, it dynamically imports the `webbluetooth` package.
* {@link https://github.com/thegecko/webbluetooth}
*
* @returns {Promise<Bluetooth>} A promise that resolves to the Bluetooth instance.
* @throws {Error} If Web Bluetooth is not available in the current environment.
*/
protected getBluetooth(): Promise<Bluetooth>;
/**
* Handles notifications received from a characteristic.
* @param {DataView} value - The notification event.
*
* @example
* device.handleNotifications(someCharacteristic);
*/
protected handleNotifications: (value: DataView) => void;
/**
* Checks if a Bluetooth device is connected.
* @returns {boolean} A boolean indicating whether the device is connected.
* @public
*
* @example
* if (device.isConnected()) {
* console.log('Device is connected');
* } else {
* console.log('Device is not connected');
* }
*/
isConnected: () => boolean;
/**
* Sets the callback function to be called when notifications are received.
* @param {NotifyCallback} callback - The callback function to be set.
* @param {ForceUnit} [unit="kg"] - Optional display unit for force values in the callback payload.
* @returns {void}
* @public
*
* @example
* device.notify((data) => {
* console.log('Received notification:', data);
* });
* device.notify((data) => { ... }, 'lbs');
*/
notify: (callback: NotifyCallback, unit?: ForceUnit) => void;
/**
* Handles the 'connected' event.
* @param {Function} onSuccess - Callback function to execute on successful connection.
* @public
*
* @example
* device.onConnected(() => {
* console.log('Device connected successfully');
* });
*/
protected onConnected: (onSuccess: () => void) => Promise<void>;
/**
* Handles the 'disconnected' event.
* @param {Event} event - The 'disconnected' event.
* @public
*
* @example
* device.onDisconnected(event);
*/
protected onDisconnected: (event: Event) => void;
/**
* Reads the value of the specified characteristic from the device.
* @param {string} serviceId - The service ID where the characteristic belongs.
* @param {string} characteristicId - The characteristic ID to read from.
* @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
* @returns {Promise<string | undefined>} A promise that resolves when the read operation is completed.
* @public
*
* @example
* const value = await device.read('battery', 'level', 1000);
* console.log('Battery level:', value);
*/
read: (serviceId: string, characteristicId: string, duration?: number) => Promise<string | undefined>;
/**
* Initiates the tare calibration process.
* @param {number} duration - The duration time for tare calibration.
* @returns {boolean} A boolean indicating whether the tare calibration was successful.
* @public
*
* @example
* const success = device.tare(5000);
* if (success) {
* console.log('Tare calibration started');
* } else {
* console.log('Tare calibration failed to start');
* }
*/
tare(duration?: number): boolean;
/**
* Clears the software tare offset and related state.
* Used by devices that implement hardware tare so applyTare does not double-adjust.
* @protected
*/
protected clearTareOffset(): void;
/**
* Apply tare calibration to the provided sample.
* @param {number} sample - The sample to calibrate.
* @returns {number} The calibrated tare value.
* @protected
*
* @example
* const calibratedSample = device.applyTare(rawSample);
* console.log('Calibrated sample:', calibratedSample);
*/
protected applyTare(sample: number): number;
/**
* Updates the timestamp of the last device interaction.
* This method sets the updatedAt property to the current date and time.
* @protected
*
* @example
* device.updateTimestamp();
* console.log('Last updated:', device.updatedAt);
*/
protected updateTimestamp: () => void;
/**
* Writes a message to the specified characteristic of a Bluetooth device and optionally provides a callback to handle responses.
* @param {string} serviceId - The service UUID of the Bluetooth device containing the target characteristic.
* @param {string} characteristicId - The characteristic UUID where the message will be written.
* @param {string | Uint8Array | undefined} message - The message to be written to the characteristic. It can be a string or a Uint8Array.
* @param {number} [duration=0] - Optional. The time in milliseconds to wait before resolving the promise. Defaults to 0 for immediate resolution.
* @param {WriteCallback} [callback=writeCallback] - Optional. A custom callback to handle the response after the write operation is successful.
* @returns {Promise<void>} A promise that resolves once the write operation is complete.
* @public
* @throws {Error} Throws an error if the characteristic is undefined.
*
* @example
* // Example usage of the write function with a custom callback
* await Progressor.write("progressor", "tx", ProgressorCommands.GET_BATTERY_VOLTAGE, 250, (data) => {
* console.log(`Battery voltage: ${data}`);
* });
*/
write: (serviceId: string, characteristicId: string, message: string | Uint8Array | undefined, duration?: number, callback?: WriteCallback) => Promise<void>;
}
//# sourceMappingURL=device.model.d.ts.map