import * as TsType from './tstype'; import {ZclDataPayload} from './events'; import events from 'events'; import {ZclFrame, FrameType, Direction} from '../zcl'; import Debug from "debug"; const debug = Debug("zigbee-herdsman:adapter"); abstract class Adapter extends events.EventEmitter { public readonly greenPowerGroup = 0x0b84; protected networkOptions: TsType.NetworkOptions; protected adapterOptions: TsType.AdapterOptions; protected serialPortOptions: TsType.SerialPortOptions; protected backupPath: string; protected constructor( networkOptions: TsType.NetworkOptions, serialPortOptions: TsType.SerialPortOptions, backupPath: string, adapterOptions: TsType.AdapterOptions) { super(); this.networkOptions = networkOptions; this.adapterOptions = adapterOptions; this.serialPortOptions = serialPortOptions; this.backupPath = backupPath; } /** * Utility */ public static async create( networkOptions: TsType.NetworkOptions, serialPortOptions: TsType.SerialPortOptions, backupPath: string, adapterOptions: TsType.AdapterOptions, ): Promise { const {ZStackAdapter} = await import('./z-stack/adapter'); const {DeconzAdapter} = await import('./deconz/adapter'); const {ZiGateAdapter} = await import('./zigate/adapter'); type AdapterImplementation = typeof ZStackAdapter | typeof DeconzAdapter | typeof ZiGateAdapter; let adapters: AdapterImplementation[]; const adapterLookup = {zstack: ZStackAdapter, deconz: DeconzAdapter, zigate: ZiGateAdapter}; if (serialPortOptions.adapter) { if (adapterLookup.hasOwnProperty(serialPortOptions.adapter)) { adapters = [adapterLookup[serialPortOptions.adapter]]; } else { throw new Error( `Adapter '${serialPortOptions.adapter}' does not exists, possible ` + `options: ${Object.keys(adapterLookup).join(', ')}` ); } } else { adapters = Object.values(adapterLookup); } // Use ZStackAdapter by default let adapter: AdapterImplementation = adapters[0]; if (!serialPortOptions.path) { debug('No path provided, auto detecting path'); for (const candidate of adapters) { const path = await candidate.autoDetectPath(); if (path) { debug(`Auto detected path '${path}' from adapter '${candidate.name}'`); serialPortOptions.path = path; adapter = candidate; break; } } if (!serialPortOptions.path) { throw new Error("No path provided and failed to auto detect path"); } } else { try { // Determine adapter to use for (const candidate of adapters) { if (await candidate.isValidPath(serialPortOptions.path)) { debug(`Path '${serialPortOptions.path}' is valid for '${candidate.name}'`); adapter = candidate; break; } } } catch (error) { debug(`Failed to validate path: '${error}'`); } } return new adapter(networkOptions, serialPortOptions, backupPath, adapterOptions); } public abstract start(): Promise; public abstract stop(): Promise; public abstract getCoordinator(): Promise; public abstract getCoordinatorVersion(): Promise; public abstract reset(type: 'soft' | 'hard'): Promise; public abstract supportsLED(): Promise; public abstract setLED(enabled: boolean): Promise; public abstract supportsBackup(): Promise; public abstract backup(): Promise; public abstract getNetworkParameters(): Promise; public abstract setTransmitPower(value: number): Promise; public abstract waitFor( networkAddress: number, endpoint: number, frameType: FrameType, direction: Direction, transactionSequenceNumber: number, clusterID: number, commandIdentifier: number, timeout: number, ): {promise: Promise; cancel: () => void}; /** * ZDO */ public abstract permitJoin(seconds: number, networkAddress: number): Promise; public abstract lqi(networkAddress: number): Promise; public abstract routingTable(networkAddress: number): Promise; public abstract nodeDescriptor(networkAddress: number): Promise; public abstract activeEndpoints(networkAddress: number): Promise; public abstract simpleDescriptor(networkAddress: number, endpointID: number): Promise; public abstract bind( destinationNetworkAddress: number, sourceIeeeAddress: string, sourceEndpoint: number, clusterID: number, destinationAddressOrGroup: string | number, type: 'endpoint' | 'group', destinationEndpoint?: number ): Promise; public abstract unbind( destinationNetworkAddress: number, sourceIeeeAddress: string, sourceEndpoint: number, clusterID: number, destinationAddressOrGroup: string | number, type: 'endpoint' | 'group', destinationEndpoint: number ): Promise; public abstract removeDevice(networkAddress: number, ieeeAddr: string): Promise; /** * ZCL */ public abstract sendZclFrameToEndpoint( ieeeAddr: string, networkAddress: number, endpoint: number, zclFrame: ZclFrame, timeout: number, disableResponse: boolean, disableRecovery: boolean, sourceEndpoint?: number, ): Promise; public abstract sendZclFrameToGroup(groupID: number, zclFrame: ZclFrame, sourceEndpoint?: number): Promise; public abstract sendZclFrameToAll(endpoint: number, zclFrame: ZclFrame, sourceEndpoint: number): Promise; /** * InterPAN */ public abstract setChannelInterPAN(channel: number): Promise; public abstract sendZclFrameInterPANToIeeeAddr(zclFrame: ZclFrame, ieeeAddress: string): Promise; public abstract sendZclFrameInterPANBroadcast( zclFrame: ZclFrame, timeout: number ): Promise; public abstract restoreChannelInterPAN(): Promise; } export default Adapter;