UNPKG

homebridge-roborock-control

Version:

A Homebridge plugin to control Roborock vacuum cleaners.

122 lines 5.68 kB
import { PyRoborockCmd, PyRoborockState } from '../roborock/roborock-api.js'; import { Log } from '../util/log.js'; import { PollingAccessory } from './pollingAccessory.js'; // Names of properties present in the DeviceState. const kVacuumState = 'state'; const kFanPower = 'fan_power'; const kBatteryLevel = 'battery'; const kCleaning = 'is_cleaning'; const kLowBattery = 'is_low_battery'; const kCharging = 'is_charging'; /** * An instance of this class is created for each Roborock accessory. */ export class RoborockAccessory extends PollingAccessory { platform; accessory; rrClient; static kLowBatteryPercent = 15; batteryService; fanService; constructor(platform, accessory, rrClient) { // Initialize the base class first, then initialize the services. super(platform, accessory); this.platform = platform; this.accessory = accessory; this.rrClient = rrClient; // // Create a Fan to control the main vacuum function. // this.fanService = (this.accessory.getService(this.platform.Service.Fan) || this.accessory.addService(this.platform.Service.Fan)); // // Add a service to report the battery level. // this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery); // // Set up the handlers for each service and characteristic. // this.setupHandlers(); } async setupHandlers() { // Convenience references to Characteristic and Service. const Characteristic = this.platform.Characteristic; // Perform a refresh of the device to establish the initial state. await this.refreshDeviceState(); // Register handlers for all dynamic characteristics. this.fanService.getCharacteristic(Characteristic.On) .onGet(() => this.getProperty(kCleaning)) .onSet((active) => this.setDeviceState(!!active)); this.batteryService.getCharacteristic(Characteristic.BatteryLevel) .onGet(() => this.getProperty(kBatteryLevel)); this.batteryService.getCharacteristic(Characteristic.ChargingState) .onGet(() => this.getProperty(kCharging)); this.batteryService.getCharacteristic(Characteristic.StatusLowBattery) .onGet(() => this.getProperty(kLowBattery)); } // Checks the given property and throws an exception if it is undefined. Used // by getters to detect a communication failure. getProperty(propertyName) { const propertyValue = this.currentState()[propertyName]; if (propertyValue === undefined) { throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */); } return propertyValue; } // Update the vacuum's state and make sure the change is reflected in Homekit. async setDeviceState(active) { Log.debug(`Setting vacuum state to ${active ? 'active' : 'inactive'}`); if (!await this.rrClient.sendCommand(active ? await PyRoborockCmd.APP_START : await PyRoborockCmd.APP_CHARGE)) { throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */); } this.refreshDeviceState(); } // // Implementations of virtual superclass methods. // // Return true if services have been initialized. servicesReady() { return !!(this.fanService && this.batteryService); } // Obtain and return the device's current state. async getDeviceState(lastState) { // If we don't get a response, set the device state to empty. const rawDeviceState = await this.rrClient.getStatus(); if (!rawDeviceState) { Log.debug('No response from device, returning empty state'); return {}; } // Otherwise, build the new device state from the response. const devState = { [kVacuumState]: await rawDeviceState[kVacuumState], [kFanPower]: await rawDeviceState[kFanPower], [kBatteryLevel]: await rawDeviceState[kBatteryLevel], }; devState[kCleaning] = (devState[kVacuumState] === await PyRoborockState.cleaning.valueOf()); devState[kLowBattery] = (devState[kBatteryLevel] <= RoborockAccessory.kLowBatteryPercent); devState[kCharging] = (devState[kVacuumState] === await PyRoborockState.charging.valueOf()); return devState; } // Push the current state to Homekit. async updateHomekitState(currentState) { // Don't try to push an update if the device state is empty. This signifies // that the most recent attempt to retrieve the device state failed. if (JSON.stringify(currentState) === JSON.stringify({})) { Log.debug('Empty device state, skipping Homekit push update'); return; } // Otherwise, update each of our services. this.fanService.updateCharacteristic(this.platform.Characteristic.On, currentState[kCleaning]); this.batteryService.updateCharacteristic(this.platform.Characteristic.BatteryLevel, currentState[kBatteryLevel]); this.batteryService.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, currentState[kLowBattery]); this.batteryService.updateCharacteristic(this.platform.Characteristic.ChargingState, currentState[kCharging]); } } //# sourceMappingURL=roborockAccessory.js.map