/** * Feature Type Definitions * Features are composable capabilities that can be attached to devices */ import type { IRetryOptions } from './index.js'; // ============================================================================ // Feature Types // ============================================================================ /** * All supported feature types */ export type TFeatureType = // Document handling | 'scan' // Can scan documents (eSCL, SANE) | 'print' // Can print documents (IPP, JetDirect) | 'fax' // Can send/receive fax | 'copy' // Can copy (scan + print combined) // Media playback | 'playback' // Can play media (audio/video) | 'volume' // Has volume control // Infrastructure | 'power' // Has power status (UPS, smart plug) | 'snmp' // SNMP queryable // DLNA | 'dlna-render' // DLNA renderer | 'dlna-serve' // DLNA server (content provider) // Smart home (protocol-agnostic: home-assistant, hue, mqtt, etc.) | 'light' // Brightness, color, effects | 'climate' // Temperature, HVAC modes | 'sensor' // Read-only state values | 'camera' // Snapshots, streams | 'cover' // Blinds, garage doors | 'switch' // Binary on/off | 'lock' // Lock/unlock | 'fan' // Speed, oscillation ; /** * Feature connection state */ export type TFeatureState = 'disconnected' | 'connecting' | 'connected' | 'error'; // ============================================================================ // Base Feature Interface // ============================================================================ /** * Base interface for all features */ export interface IFeature { /** Feature type identifier */ readonly type: TFeatureType; /** Protocol used by this feature */ readonly protocol: string; /** Current feature state */ readonly state: TFeatureState; /** Port used by this feature (may differ from device port) */ readonly port: number; /** Connect to the feature endpoint */ connect(): Promise; /** Disconnect from the feature endpoint */ disconnect(): Promise; } /** * Feature info for serialization */ export interface IFeatureInfo { type: TFeatureType; protocol: string; port: number; state: TFeatureState; } // ============================================================================ // Scan Feature // ============================================================================ export type TScanProtocol = 'escl' | 'sane' | 'wia'; export type TScanFormat = 'png' | 'jpeg' | 'pdf' | 'tiff'; export type TColorMode = 'color' | 'grayscale' | 'blackwhite'; export type TScanSource = 'flatbed' | 'adf' | 'adf-duplex'; export interface IScanCapabilities { resolutions: number[]; formats: TScanFormat[]; colorModes: TColorMode[]; sources: TScanSource[]; maxWidth: number; // mm maxHeight: number; // mm minWidth: number; // mm minHeight: number; // mm } export interface IScanArea { x: number; // X offset in mm y: number; // Y offset in mm width: number; // Width in mm height: number; // Height in mm } export interface IScanOptions { resolution?: number; format?: TScanFormat; colorMode?: TColorMode; source?: TScanSource; area?: IScanArea; intent?: 'document' | 'photo' | 'preview'; quality?: number; // 1-100 for JPEG } export interface IScanResult { data: Buffer; format: TScanFormat; width: number; height: number; resolution: number; colorMode: TColorMode; mimeType: string; } export interface IScanFeatureInfo extends IFeatureInfo { type: 'scan'; protocol: TScanProtocol; supportedFormats: TScanFormat[]; supportedResolutions: number[]; supportedColorModes: TColorMode[]; supportedSources: TScanSource[]; hasAdf: boolean; hasDuplex: boolean; } // ============================================================================ // Print Feature // ============================================================================ export type TPrintProtocol = 'ipp' | 'jetdirect' | 'lpd'; export type TPrintSides = 'one-sided' | 'two-sided-long-edge' | 'two-sided-short-edge'; export type TPrintQuality = 'draft' | 'normal' | 'high'; export type TPrintColorMode = 'color' | 'monochrome'; export interface IPrintCapabilities { colorSupported: boolean; duplexSupported: boolean; mediaSizes: string[]; mediaTypes: string[]; resolutions: number[]; maxCopies: number; sidesSupported: TPrintSides[]; qualitySupported: TPrintQuality[]; } export interface IPrintOptions { copies?: number; mediaSize?: string; mediaType?: string; sides?: TPrintSides; quality?: TPrintQuality; colorMode?: TPrintColorMode; jobName?: string; } export interface IPrintJob { id: number; name: string; state: 'pending' | 'processing' | 'completed' | 'canceled' | 'aborted'; stateReason?: string; createdAt: Date; completedAt?: Date; pagesPrinted?: number; pagesTotal?: number; } export interface IPrintFeatureInfo extends IFeatureInfo { type: 'print'; protocol: TPrintProtocol; supportsColor: boolean; supportsDuplex: boolean; supportedMediaSizes: string[]; } // ============================================================================ // Playback Feature // ============================================================================ export type TPlaybackProtocol = 'sonos' | 'airplay' | 'chromecast' | 'dlna'; export type TPlaybackState = 'playing' | 'paused' | 'stopped' | 'buffering' | 'unknown'; export interface ITrackInfo { title?: string; artist?: string; album?: string; albumArtUri?: string; duration?: number; // seconds uri?: string; } export interface IPlaybackStatus { state: TPlaybackState; position: number; // seconds duration: number; // seconds track?: ITrackInfo; } export interface IPlaybackFeatureInfo extends IFeatureInfo { type: 'playback'; protocol: TPlaybackProtocol; supportsQueue: boolean; supportsSeek: boolean; } // ============================================================================ // Volume Feature // ============================================================================ export interface IVolumeFeatureInfo extends IFeatureInfo { type: 'volume'; minVolume: number; maxVolume: number; volumeStep: number; supportsMute: boolean; } // ============================================================================ // Power Feature (UPS, Smart Plugs) // ============================================================================ export type TPowerProtocol = 'nut' | 'snmp' | 'smart-plug'; export type TPowerStatus = 'online' | 'onbattery' | 'lowbattery' | 'charging' | 'discharging' | 'bypass' | 'offline' | 'error' | 'unknown'; export interface IBatteryInfo { charge: number; // 0-100% runtime: number; // seconds remaining voltage?: number; // volts temperature?: number; // celsius health?: 'good' | 'weak' | 'replace'; } export interface IPowerInfo { inputVoltage?: number; outputVoltage?: number; inputFrequency?: number; outputFrequency?: number; load?: number; // 0-100% power?: number; // watts } export interface IPowerFeatureInfo extends IFeatureInfo { type: 'power'; protocol: TPowerProtocol; hasBattery: boolean; supportsShutdown: boolean; supportsTest: boolean; } // ============================================================================ // SNMP Feature // ============================================================================ export type TSnmpVersion = 'v1' | 'v2c' | 'v3'; export interface ISnmpVarbind { oid: string; type: number; value: unknown; } export interface ISnmpFeatureInfo extends IFeatureInfo { type: 'snmp'; version: TSnmpVersion; community?: string; // for v1/v2c sysDescr?: string; sysName?: string; sysLocation?: string; } // ============================================================================ // DLNA Render Feature // ============================================================================ export interface IDlnaTransportInfo { state: 'STOPPED' | 'PLAYING' | 'PAUSED' | 'TRANSITIONING' | 'NO_MEDIA_PRESENT'; status: string; speed: string; } export interface IDlnaPositionInfo { track: number; trackDuration: string; trackMetaData?: string; trackUri?: string; relTime: string; absTime: string; } export interface IDlnaRenderFeatureInfo extends IFeatureInfo { type: 'dlna-render'; udn: string; friendlyName: string; supportsVolume: boolean; supportedProtocols: string[]; } // ============================================================================ // DLNA Server Feature // ============================================================================ export interface IDlnaContentItem { id: string; parentId: string; title: string; class: string; restricted: boolean; uri?: string; albumArtUri?: string; duration?: string; size?: number; isContainer: boolean; childCount?: number; } export interface IDlnaBrowseResult { items: IDlnaContentItem[]; numberReturned: number; totalMatches: number; updateId: number; } export interface IDlnaServeFeatureInfo extends IFeatureInfo { type: 'dlna-serve'; udn: string; friendlyName: string; contentCount?: number; } // ============================================================================ // Discovery Types // ============================================================================ /** * Feature discovered during network scan or mDNS/SSDP */ export interface IDiscoveredFeature { type: TFeatureType; protocol: string; port: number; metadata: Record; } /** * Options for creating a feature instance */ export interface IFeatureOptions { retryOptions?: IRetryOptions; metadata?: Record; }