UNPKG

homebridge-vesync-v2

Version:

A Homebridge plugin for controlling VeSync smart devices including outlets, air purifiers, and humidifiers

153 lines (136 loc) 4.9 kB
"use strict"; const BaseDevice = require('./BaseDevice'); class FanDevice extends BaseDevice { constructor(accessory, client, log, debug, Service, Characteristic) { super(accessory, client, log, debug, Service, Characteristic); } configureService() { if (!this.accessory) { throw new Error('Accessory is not initialized'); } // Fan service const fanService = this.accessory.getService(this.Service.Fan) || this.accessory.addService(this.Service.Fan, this.accessory.context.name); // Required characteristics fanService.getCharacteristic(this.Characteristic.On) .on('get', this.getPowerState.bind(this)) .on('set', this.setPowerState.bind(this)); fanService.getCharacteristic(this.Characteristic.RotationSpeed) .setProps({ minValue: 0, maxValue: 100, minStep: 8.33 // 100/12 for 12 speed levels }) .on('get', this.getRotationSpeed.bind(this)) .on('set', this.setRotationSpeed.bind(this)); fanService.getCharacteristic(this.Characteristic.SwingMode) .on('get', this.getSwingMode.bind(this)) .on('set', this.setSwingMode.bind(this)); } // Helper method to get fan status async _getStatus() { if (!this.client) { throw new Error('Client is not initialized'); } const response = await this.client.bypassV2({ method: 'getTowerFanStatus', source: 'APP' }); if (!response || !response.data) { throw new Error('Invalid response from device'); } // Cache the status data this.lastStatus = response.data; return response; } async getPowerState(callback) { try { const status = await this._getStatus(); if (!status.data || typeof status.data.powerSwitch === 'undefined') { throw new Error('Invalid power state data'); } callback(null, status.data.powerSwitch === 1); } catch (error) { this.log.error('Error getting power state:', error); callback(error); } } async setPowerState(value, callback) { try { await this.client.bypassV2({ data: { powerSwitch: value ? 1 : 0, switchIdx: 0 }, method: 'setSwitch', source: 'APP' }); callback(); } catch (error) { this.log.error('Error setting power state:', error); callback(error); } } async getRotationSpeed(callback) { try { const status = await this._getStatus(); if (!status.data || typeof status.data.manualSpeedLevel === 'undefined') { throw new Error('Invalid speed data'); } // Convert 1-12 to 0-100 const speed = status.data.manualSpeedLevel; const percentage = Math.round((speed / 12) * 100); callback(null, percentage); } catch (error) { this.log.error('Error getting rotation speed:', error); callback(error); } } async setRotationSpeed(value, callback) { try { // Convert 0-100 to 1-12 const level = Math.max(1, Math.min(12, Math.round((value / 100) * 12))); await this.client.bypassV2({ data: { manualSpeedLevel: level, levelType: 'wind', levelIdx: 0 }, method: 'setLevel', source: 'APP' }); callback(); } catch (error) { this.log.error('Error setting rotation speed:', error); callback(error); } } async getSwingMode(callback) { try { const status = await this._getStatus(); if (!status.data || typeof status.data.oscillationSwitch === 'undefined') { throw new Error('Invalid swing mode data'); } callback(null, status.data.oscillationSwitch === 1); } catch (error) { this.log.error('Error getting swing mode:', error); callback(error); } } async setSwingMode(value, callback) { try { await this.client.bypassV2({ data: { oscillationSwitch: value ? 1 : 0 }, method: 'setOscillationSwitch', source: 'APP' }); callback(); } catch (error) { this.log.error('Error setting swing mode:', error); callback(error); } } } module.exports = FanDevice;