UNPKG

homebridge-dooyashade

Version:
163 lines 7.81 kB
import { DooyashadePlatformAccessory } from './platformAccessory.js'; import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js'; import { TCPManager, CRC16 } from './utils.js'; import { ShadeCommand } from './commands.js'; export class DooyashadeHomebridgePlatform { log; config; api; Service; Characteristic; // this is used to track restored cached accessories accessories = new Map(); discoveredCacheUUIDs = []; tcpManagers = new Map(); pollingIntervals = new Map(); constructor(log, config, api) { this.log = log; this.config = config; this.api = api; this.Service = api.hap.Service; this.Characteristic = api.hap.Characteristic; this.log.debug('Finished initializing platform:', this.config.name); // When this event is fired it means Homebridge has restored all cached accessories from disk. // Dynamic Platform plugins should only register new accessories after this event was fired, // in order to ensure they weren't added to homebridge already. This event can also be used // to start discovery of new accessories. this.api.on('didFinishLaunching', () => { log.debug('Executed didFinishLaunching callback'); // run the method to discover / register your devices as accessories this.discoverDevices(); }); } configureAccessory(accessory) { this.log.info('Loading accessory from cache:', accessory.displayName); this.accessories.set(accessory.UUID, accessory); } setupTCPManager(hubConfig) { const key = `${hubConfig.HostIP}:${hubConfig.HostPort}`; if (this.tcpManagers.has(key)) { const existingManager = this.tcpManagers.get(key); if (existingManager) { this.log.debug(`Reusing existing TCP manager for ${key}`); return; } } this.log.info(`Setting up new TCP manager for ${hubConfig.HostIP}:${hubConfig.HostPort}`); const tcpManager = new TCPManager(hubConfig.HostIP, hubConfig.HostPort, this.log, (data) => this.handleTCPData(data, hubConfig), () => this.handleTCPConnect(hubConfig), () => this.handleTCPDisconnect(hubConfig)); this.tcpManagers.set(key, tcpManager); tcpManager.connect(); this.log.info(`TCP manager connection initiated for ${key}`); } handleTCPData(data, hubConfig) { this.log.debug('Received raw data:', data.toString('hex')); if (!CRC16.verify(data)) { this.log.warn('Invalid CRC in received data'); this.log.debug('CRC verification failed for data:', data.toString('hex')); return; } this.log.debug('CRC verification passed'); const response = ShadeCommand.parseResponse(data); this.log.debug('Parsed response:', response); if (!response.isValid) { this.log.warn('Invalid response format'); this.log.debug('Invalid response details:', response); return; } this.log.info('Valid response received from device:', { address1: response.address1, address2: response.address2, position: response.position, raw: data.toString('hex'), }); // 查找对应的配件并更新状态 for (const shade of hubConfig.shades) { if (shade.address.address1 === response.address1 && shade.address.address2 === response.address2) { const uuid = this.generateUUID(hubConfig, shade); const accessory = this.accessories.get(uuid); if (accessory) { const handler = new DooyashadePlatformAccessory(this, accessory); const position = ShadeCommand.convertPosition(response.position); handler.updateCurrentPosition(position); } break; } } } handleTCPConnect(hubConfig) { this.log.info(`Connected to hub at ${hubConfig.HostIP}:${hubConfig.HostPort}`); // 连接成功后查询所有窗帘的状态 for (const shade of hubConfig.shades) { const uuid = this.generateUUID(hubConfig, shade); const accessory = this.accessories.get(uuid); if (accessory) { this.log.debug(`Querying position for shade: ${shade.name} (${uuid})`); const handler = new DooyashadePlatformAccessory(this, accessory); setTimeout(() => { handler.queryPosition(); }, 1000); // 延迟1秒查询,确保连接稳定 } else { this.log.warn(`Accessory not found for shade: ${shade.name} (${uuid})`); } } } handleTCPDisconnect(hubConfig) { this.log.warn(`Disconnected from hub at ${hubConfig.HostIP}:${hubConfig.HostPort}`); } generateUUID(hubConfig, shade) { return this.api.hap.uuid.generate(`${hubConfig.HostIP}:${hubConfig.HostPort}:${shade.address.address1}:${shade.address.address2}`); } getTCPManager(hubConfig) { const key = `${hubConfig.HostIP}:${hubConfig.HostPort}`; return this.tcpManagers.get(key); } discoverDevices() { const hubs = this.config.hubs; if (!Array.isArray(hubs)) { this.log.error('No hubs configured'); return; } for (const hub of hubs) { this.setupTCPManager(hub); for (const shade of hub.shades) { const uuid = this.generateUUID(hub, shade); const existingAccessory = this.accessories.get(uuid); if (existingAccessory) { this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName); existingAccessory.context.device = { hub, shade }; this.api.updatePlatformAccessories([existingAccessory]); new DooyashadePlatformAccessory(this, existingAccessory); } else { this.log.info('Adding new accessory:', shade.name); const accessory = new this.api.platformAccessory(shade.name, uuid); accessory.context.device = { hub, shade }; new DooyashadePlatformAccessory(this, accessory); this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); } this.discoveredCacheUUIDs.push(uuid); // 设置状态轮询定时器 const pollingInterval = parseInt(this.config.statePollingInterval || '10', 10); const intervalKey = `${hub.HostIP}:${hub.HostPort}:${shade.address.address1}:${shade.address.address2}`; if (this.pollingIntervals.has(intervalKey)) { clearInterval(this.pollingIntervals.get(intervalKey)); } this.pollingIntervals.set(intervalKey, setInterval(() => { const accessory = this.accessories.get(uuid); if (accessory) { const handler = new DooyashadePlatformAccessory(this, accessory); handler.queryPosition(); } }, pollingInterval * 60 * 1000)); } } for (const [uuid, accessory] of this.accessories) { if (!this.discoveredCacheUUIDs.includes(uuid)) { this.log.info('Removing existing accessory from cache:', accessory.displayName); this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); } } } } //# sourceMappingURL=platform.js.map