import type { ConfigItemAny } from '@iobroker/dm-utils'; import type * as i2c from 'i2c-bus'; import type { I2CDeviceConfig, ImplementationConfigBase } from '../lib/adapter-config'; import type { PollingCallback } from '../lib/async'; import { Polling } from '../lib/async'; import { toHexString } from '../lib/shared'; import type { I2cAdapter, StateValue } from '../main'; export interface DeviceHandlerInfo { type: string; createHandler: (deviceConfig: I2CDeviceConfig, adapter: I2cAdapter) => DeviceHandlerBase; config: Record; names: { name: string; addresses: number[]; config?: Record; }[]; } export abstract class DeviceHandlerBase { public readonly type: string; public readonly name: string; public readonly hexAddress: string; protected readonly config: T; private polling?: Polling; constructor( public readonly deviceConfig: I2CDeviceConfig, protected readonly adapter: I2cAdapter, ) { if (!deviceConfig.type || !deviceConfig.name) { throw new Error('Type and name of device must be specified'); } this.type = deviceConfig.type; this.name = deviceConfig.name; this.config = deviceConfig[deviceConfig.type] as T; this.hexAddress = toHexString(deviceConfig.address); } public get address(): number { return this.deviceConfig.address; } // methods to override /** Starts the device handler. */ abstract startAsync(): Promise; /** Stops the device handler. */ abstract stopAsync(): Promise; // polling related methods protected startPolling(callback: PollingCallback, interval: number, minInterval?: number): void { this.stopPolling(); this.polling = new Polling(callback); this.polling.runAsync(interval, minInterval).catch(error => this.error(`Polling error: ${error}`)); } protected stopPolling(): void { this.polling?.stop(); } // I2C related methods protected async deviceId(): Promise { return await this.adapter.i2cBus.deviceId(this.deviceConfig.address); } protected async i2cRead(length: number, buffer: Buffer): Promise { const result = await this.adapter.i2cBus.i2cRead(this.deviceConfig.address, length, buffer); this.silly(`i2cRead(${length}): 0x${result.buffer.toString('hex')}`); return result; } protected async i2cWrite(length: number, buffer: Buffer): Promise { this.silly(`i2cWrite(${length}, 0x${buffer.toString('hex')})`); return await this.adapter.i2cBus.i2cWrite(this.deviceConfig.address, length, buffer); } protected async readByte(command: number): Promise { const byte = await this.adapter.i2cBus.readByte(this.deviceConfig.address, command); this.silly(`readByte(${toHexString(command)}): ${toHexString(byte)}`); return byte; } protected async readI2cBlock(command: number, length: number, buffer: Buffer): Promise { const result = await this.adapter.i2cBus.readI2cBlock(this.deviceConfig.address, command, length, buffer); this.silly(`readI2cBlock(${toHexString(command)}, ${length}): 0x${result.buffer.toString('hex')}`); return result; } protected async receiveByte(): Promise { const byte = await this.adapter.i2cBus.receiveByte(this.deviceConfig.address); this.silly(`receiveByte(): ${toHexString(byte)}`); return byte; } protected async sendByte(byte: number): Promise { this.silly(`sendByte(${toHexString(byte)})`); return await this.adapter.i2cBus.sendByte(this.deviceConfig.address, byte); } protected async writeByte(command: number, byte: number): Promise { this.silly(`writeByte(${toHexString(command)}, ${toHexString(byte)})`); return await this.adapter.i2cBus.writeByte(this.deviceConfig.address, command, byte); } protected async writeQuick(command: number, bit: number): Promise { this.silly(`writeQuick(${toHexString(command)}, ${bit})`); return await this.adapter.i2cBus.writeQuick(this.deviceConfig.address, command, bit); } protected async writeI2cBlock(command: number, length: number, buffer: Buffer): Promise { this.silly(`writeI2cBlock(${toHexString(command)}, ${length}, 0x${buffer.toString('hex')})`); return await this.adapter.i2cBus.writeI2cBlock(this.deviceConfig.address, command, length, buffer); } // adapter methods protected async setStateAckAsync(state: string | number, value: T): Promise { await this.adapter.setStateAckAsync(`${this.hexAddress}.${state}`, value); } protected getStateValue(state: string | number): T | undefined { return this.adapter.getStateValue(`${this.hexAddress}.${state}`); } // logging methods protected silly(message: string): void { this.adapter.log.silly(`${this.type} ${this.hexAddress}: ${message}`); } protected debug(message: string): void { this.adapter.log.debug(`${this.type} ${this.hexAddress}: ${message}`); } protected info(message: string): void { this.adapter.log.info(`${this.type} ${this.hexAddress}: ${message}`); } protected warn(message: string): void { this.adapter.log.warn(`${this.type} ${this.hexAddress}: ${message}`); } protected error(message: string): void { this.adapter.log.error(`${this.type} ${this.hexAddress}: ${message}`); } }