UNPKG

homebridge-xiaomi-roborock-vacuum

Version:

Xiaomi Vacuum Cleaner - 1st (Mi Robot), 2nd (Roborock S50 + S55), 3rd Generation (Roborock S6) and S5 Max - plugin for Homebridge.

189 lines 9.17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MainService = void 0; const rxjs_1 = require("rxjs"); const find_speed_modes_1 = require("../utils/find_speed_modes"); const plugin_service_class_1 = require("./plugin_service_class"); const ensure_name_1 = require("../utils/ensure_name"); class MainService extends plugin_service_class_1.PluginServiceClass { productInfo; roomsService; setWaterSpeed; changedPause; cachedState = new Map(); service; constructor(coreContext, productInfo, roomsService, setWaterSpeed, changedPause) { super(coreContext); this.productInfo = productInfo; this.roomsService = roomsService; this.setWaterSpeed = setWaterSpeed; this.changedPause = changedPause; if (this.config.serviceType === "fan") { this.service = new this.hap.Service.Fan(this.config.name, "Vacuum"); this.service .getCharacteristic(this.hap.Characteristic.RotationSpeed) .onGet(() => this.getSpeed()) .onSet((newState) => this.setSpeed(newState)); } else { this.service = new this.hap.Service.Switch(this.config.name, "Vacuum"); } (0, ensure_name_1.ensureName)(this.hap, this.service, this.config.name); if (this.service.setPrimaryService) this.service.setPrimaryService(true); this.service .getCharacteristic(this.hap.Characteristic.On) .onGet(() => this.getCleaning()) .onSet((newState) => this.setCleaning(newState)) .on("change", ({ newValue }) => { this.changedPause(newValue === true); }); } async init() { if (this.config.serviceType === "fan") { this.deviceManager.deviceConnected$.subscribe(() => { // Now that we know the model, amend the steps in the Rotation speed (for better usability) const minStep = 100 / ((0, find_speed_modes_1.findSpeedModes)(this.deviceManager.model).speed.length - 1); this.service .getCharacteristic(this.hap.Characteristic.RotationSpeed) .setProps({ minStep: minStep }); }); this.deviceManager.stateChanged$ .pipe((0, rxjs_1.filter)(({ key }) => key === "fanSpeed"), (0, rxjs_1.distinct)(({ value }) => value)) .subscribe(({ value: speed }) => { this.log.info(`MON changedSpeed | FanSpeed is now ${speed}%`); const speedMode = this.findSpeedModeFromMiio(speed); if (typeof speedMode === "undefined") { this.log.warn(`WAR changedSpeed | Speed was changed to ${speed}%, this speed is not supported`); } else { const { homekitTopLevel, name } = speedMode; this.log.info(`changedSpeed | Speed was changed to ${speed}% (${name}), for HomeKit ${homekitTopLevel}%`); this.service .getCharacteristic(this.hap.Characteristic.RotationSpeed) .updateValue(homekitTopLevel); } }); } this.deviceManager.stateChanged$ .pipe((0, rxjs_1.filter)(({ key }) => key === "cleaning"), (0, rxjs_1.map)(({ value }) => value === true), (0, rxjs_1.tap)((isCleaning) => { this.log.debug(`MON changedCleaning | CleaningState is now ${isCleaning}`); this.service .getCharacteristic(this.hap.Characteristic.On) .updateValue(isCleaning); }), (0, rxjs_1.distinct)()) .subscribe((isCleaning) => { this.log.info(`changedCleaning | Cleaning is ${isCleaning ? "ON" : "OFF"}.`); }); } get services() { return [this.service]; } async getCleaning() { try { const isCleaning = this.deviceManager.isCleaning; this.log.info(`getCleaning | Cleaning is ${isCleaning}`); return isCleaning; } catch (err) { this.log.error(`getCleaning | Failed getting the cleaning status.`, err); throw err; } } async setCleaning(state) { await this.deviceManager.ensureDevice("setCleaning"); this.log.info(`ACT setCleaning | Set cleaning to ${state}}`); try { if (state && !this.deviceManager.isCleaning) { // Start cleaning const roomIdsToClean = this.roomsService.roomIdsToClean; if (roomIdsToClean.size > 0) { await this.deviceManager.device.cleanRooms(Array.from(roomIdsToClean)); this.log.info(`ACT setCleaning | Start rooms cleaning for rooms ${Array.from(roomIdsToClean)}, device is in state ${this.deviceManager.property("state")}.`); } else { await this.deviceManager.device.activateCleaning(); this.log.info(`ACT setCleaning | Start full cleaning, device is in state ${this.deviceManager.property("state")}.`); } } else if (!state && (this.deviceManager.isCleaning || this.deviceManager.isPaused)) { // Stop cleaning this.log.info(`ACT setCleaning | Stop cleaning and go to charge, device is in state ${this.deviceManager.property("state")}`); await this.deviceManager.device.activateCharging(); } } catch (err) { this.log.error(`setCleaning | Failed to set cleaning to ${state}`, err); throw err; } } async getSpeed() { await this.deviceManager.ensureDevice("getSpeed"); const speed = await this.deviceManager.device.fanSpeed(); this.log.info(`getSpeed | Fanspeed is ${speed} over miIO. Converting to HomeKit`); const { homekitTopLevel, name } = this.findSpeedModeFromMiio(speed) || {}; this.log.info(`getSpeed | FanSpeed is ${speed} over miIO "${name}" > HomeKit speed ${homekitTopLevel}%`); return homekitTopLevel || 0; } async setSpeed(speed) { await this.deviceManager.ensureDevice("setSpeed"); if (typeof speed === "number") { this.log.debug(`ACT setSpeed | Speed got ${speed}% over HomeKit > CLEANUP.`); } // Get the speed modes for this model const speedModes = (0, find_speed_modes_1.findSpeedModes)(this.deviceManager.model, this.productInfo.firmware).speed; let miLevel = null; let name = null; if (typeof speed === "number") { // Speed set by number // gen1 has maximum of 91%, so anything over that won't work. Getting safety maximum. const safeSpeed = Math.min(speed, speedModes[speedModes.length - 1].homekitTopLevel); // Find the minimum homekitTopLevel that matches the desired speed const speedMode = speedModes.find((mode) => safeSpeed <= mode.homekitTopLevel); miLevel = speedMode.miLevel; name = speedMode.name; } else { // Set by mode name const speedMode = speedModes.find((mode) => mode.name === speed); if (speedMode == null) { this.log.info(`setSpeed | Mode "${speed}" does not exist.`); return; } miLevel = speedMode.miLevel; name = speedMode.name; } this.log.info(`ACT setSpeed | FanSpeed set to ${miLevel} over miIO for "${name}".`); // Save the latest set speed for handling the "custom" speed later this.cachedState.set("FanSpeed", miLevel); this.cachedState.set("FanSpeedName", name); if (miLevel === -1) { this.log.info(`setSpeed | FanSpeed is -1 => Calling setCleaning(false) instead of changing the fan speed`); await this.setCleaning(false); } else { await this.deviceManager.device.changeFanSpeed(miLevel); // If speed is "custom", also set the water speed to "custom" (for Xiaomi App) if (name === "Custom" && this.config.waterBox && this.cachedState.get("WaterSpeedName") !== "Custom") { await this.setWaterSpeed("Custom"); } // If speed is not "custom" remove set the water speed also to a fixed value (for Xiaomi App) else if (name !== "Custom" && this.config.waterBox && this.cachedState.get("WaterSpeedName") === "Custom") { await this.setWaterSpeed("Medium"); } } } findSpeedModeFromMiio(speed) { // Get the speed modes for this model const speedModes = (0, find_speed_modes_1.findSpeedModes)(this.deviceManager.model, this.productInfo.firmware).speed; // Find speed mode that matches the miLevel return speedModes.find((mode) => mode.miLevel === speed); } } exports.MainService = MainService; //# sourceMappingURL=main_service.js.map