UNPKG

homebridge-roborock-maisun

Version:

Homebridge plugin for Xiaomi Roborock (2nd generation) vacuum cleaner with zone cleaning and go to target functions

716 lines (715 loc) 30.2 kB
var miio = require('miio'); var util = require('util'); var Accessory, Service, Characteristic, UUIDGen, IntervalID; module.exports = function(homebridge) { Accessory = homebridge.platformAccessory; Service = homebridge.hap.Service; Characteristic = homebridge.hap.Characteristic; UUIDGen = homebridge.hap.uuid; homebridge.registerAccessory('homebridge-roborock-maisun', 'RoborockVacuum', RoborockVacuum); } function RoborockVacuum(log, config) { var that = this; that.services = []; that.log = log; that.name = config.name || 'Roborock Vacuum Cleaner'; that.ip = config.ip; that.token = config.token; that.pause = config.pause; that.dock = config.dock; that.zones = config.zones; that.target = config.target; that.device = null; that.startup = true; that.zoneCleaning = false; that.goingTo = false; that.speed = 0; if (!that.ip) throw new Error('You must provide an ip address of the vacuum cleaner.'); if (!that.token) throw new Error('You must provide a token of the vacuum cleaner.'); if (that.zones) { that.zonesWithRepeats = []; for (var zone of that.zones) { if (zone.length == 4) { that.zonesWithRepeats.push(zone.concat(1)); } else if (zone.length == 5) { that.zonesWithRepeats.push(zone); } } } // set zones, if not set do whole floor that.speedmodes = [ 0, //Off 105, // Mop 38, // Quiet 60, // Balanced 75, //Turbo 100 // MAX ]; that.errors = { id1: { description: 'Try turning the orange laserhead to make sure it isnt blocked.' }, id2: { description: 'Clean and tap the bumpers lightly.' }, id3: { description: 'Try moving the vacuum to a different place.' }, id4: { description: 'Wipe the cliff sensor clean and move the vacuum to a different place.' }, id5: { description: 'Remove and clean the main brush.' }, id6: { description: 'Remove and clean the sidebrushes.' }, id7: { description: 'Make sure the wheels arent blocked. Move the vacuum to a different place and try again.' }, id8: { description: 'Make sure there are no obstacles around the vacuum.' }, id9: { description: 'Install the dustbin and the filter.' }, id10: { description: 'Make sure the filter has been tried or clean the filter.' }, id11: { description: 'Strong magnetic field detected. Move the device away from the virtual wall and try again' }, id12: { description: 'Battery is low, charge your vacuum.' }, id13: { description: 'Couldnt charge properly. Make sure the charging surfaces are clean.' }, id14: { description: 'Battery malfunctioned.' }, id15: { description: 'Wipe the wall sensor clean.' }, id16: { description: 'Use the vacuum on a flat horizontal surface.' }, id17: { description: 'Sidebrushes malfunctioned. Reboot the system.' }, id18: { description: 'Fan malfunctioned. Reboot the system.' }, id19: { description: 'The docking station is not connected to power.' }, id20: { description: 'unkown' }, id21: { description: 'Please make sure that the top cover of the laser distance sensor is not pinned.' }, id22: { description: 'Please wipe the dock sensor.' }, id23: { description: 'Make sure the signal emission area of dock is clean.' } }; // HOMEKIT SERVICES that.serviceInfo = new Service.AccessoryInformation(); that.serviceInfo.setCharacteristic(Characteristic.Manufacturer, 'Xiaomi').setCharacteristic(Characteristic.Model, 'Roborock S5') that.services.push(that.serviceInfo); that.fanService = new Service.Fan(that.name, 'MainFan'); that.fanService.getCharacteristic(Characteristic.RotationSpeed).setProps({ minValue: 0, maxValue: 5, minStep: 1, }).on('get', that.getSpeed.bind(that)).on('set', that.setSpeed.bind(that)); that.fanService.getCharacteristic(Characteristic.On).on('get', that.getCleaning.bind(that)).on('set', that.setCleaning.bind(that)); that.services.push(that.fanService); if (that.zones) { that.fanServiceZones = new Service.Fan(that.name + ' Zones', 'ZonesFan'); that.fanServiceZones.getCharacteristic(Characteristic.RotationSpeed).setProps({ minValue: 0, maxValue: 5, minStep: 1, }).on('get', that.getSpeed.bind(that)).on('set', that.setSpeed.bind(that)); that.fanServiceZones.getCharacteristic(Characteristic.On).on('get', that.getZoneCleaning.bind(that)).on('set', that.setZoneCleaning.bind(that)); that.services.push(that.fanServiceZones); } if (that.target) { that.targetService = new Service.Switch(that.name + ' Goto', 'GotoSwitch'); that.targetService.getCharacteristic(Characteristic.On).on('get', that.getGotoTarget.bind(that)).on('set', that.setGotoTarget.bind(that)); that.services.push(that.targetService); } that.batteryService = new Service.BatteryService(that.name + ' Battery'); that.batteryService.getCharacteristic(Characteristic.BatteryLevel).on('get', that.getBattery.bind(that)); that.batteryService.getCharacteristic(Characteristic.ChargingState).on('get', that.getCharging.bind(that)); that.batteryService.getCharacteristic(Characteristic.StatusLowBattery).on('get', that.getBatteryLow.bind(that)); that.services.push(that.batteryService); if (that.pause) { that.pauseService = new Service.Switch(that.name + ' Pause', 'PauseSwitch'); that.pauseService.getCharacteristic(Characteristic.On).on('get', that.getPausestate.bind(that)).on('set', that.setPausestate.bind(that)); that.services.push(that.pauseService); } if (that.dock) { that.dockService = new Service.OccupancySensor(that.name + ' Dock'); that.dockService.getCharacteristic(Characteristic.OccupancyDetected).on('get', that.getCharging.bind(that)); that.services.push(that.dockService); } // ADDITIONAL HOMEKIT SERVICES Characteristic.CareSensors = function() { Characteristic.call(this, 'Care indicator sensors', '00000101-0000-0000-0000-000000000000'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: '%', perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); }; util.inherits(Characteristic.CareSensors, Characteristic); Characteristic.CareSensors.UUID = '00000101-0000-0000-0000-000000000000'; Characteristic.CareFilter = function() { Characteristic.call(this, 'Care indicator filter', '00000102-0000-0000-0000-000000000000'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: '%', perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); }; util.inherits(Characteristic.CareFilter, Characteristic); Characteristic.CareFilter.UUID = '00000102-0000-0000-0000-000000000000'; Characteristic.CareSideBrush = function() { Characteristic.call(this, 'Care indicator side brush', '00000103-0000-0000-0000-000000000000'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: '%', perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); }; util.inherits(Characteristic.CareSideBrush, Characteristic); Characteristic.CareSideBrush.UUID = '00000103-0000-0000-0000-000000000000'; Characteristic.CareMainBrush = function() { Characteristic.call(this, 'Care indicator main brush', '00000104-0000-0000-0000-000000000000'); this.setProps({ format: Characteristic.Formats.FLOAT, unit: '%', perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); }; util.inherits(Characteristic.CareMainBrush, Characteristic); Characteristic.CareMainBrush.UUID = '00000104-0000-0000-0000-000000000000'; Service.Care = function(displayName, subtype) { Service.call(this, displayName, '00000111-0000-0000-0000-000000000000', subtype); this.addCharacteristic(Characteristic.CareSensors); this.addCharacteristic(Characteristic.CareFilter); this.addCharacteristic(Characteristic.CareSideBrush); this.addCharacteristic(Characteristic.CareMainBrush); }; util.inherits(Service.Care, Service); Service.Care.UUID = '00000111-0000-0000-0000-000000000000'; that.Care = new Service.Care(that.name + ' Care') that.Care.getCharacteristic(Characteristic.CareSensors).on('get', that.getCareSensors.bind(that)); that.Care.getCharacteristic(Characteristic.CareFilter).on('get', that.getCareFilter.bind(that)); that.Care.getCharacteristic(Characteristic.CareSideBrush).on('get', that.getCareSideBrush.bind(that)); that.Care.getCharacteristic(Characteristic.CareMainBrush).on('get', that.getCareMainBrush.bind(that)); that.services.push(that.Care); // (HOMEKIT) SERVICES CHANGES this.changedError = function(roboterror) { if (!roboterror.description.toLowerCase().startsWith("unknown")) { roboterrortxt = roboterror.description; } else { if (that.errors.hasOwnProperty('id' + roboterror.id)) { roboterrortxt = that.errors['id' + roboterror.id].description; //roboterrortxt = that.errors.id2.description; } else { roboterrortxt = 'Unkown ERR | errorid cant be mapped. (' + roboterror.id + ')'; } } log.warn('WARN | changedError | ' + that.model + ' | Robot has an ERROR - ' + roboterror.id + ', ' + roboterrortxt); } this.changedCleaning = function(robotcleaning) { log.debug('DEBUG | changedCleaning | ' + that.model + ' | CleaningState ' + robotcleaning); if (robotcleaning !== that.cleaning) { log.info('INFO | changedCleaning | ' + that.model + ' | Cleaning state is changed to ' + robotcleaning); that.cleaning = robotcleaning; //Stop cleaning turn off both fanse if (!that.cleaning) { that.zoneCleaning = false; that.fanService.getCharacteristic(Characteristic.On).updateValue(false); if (that.zones) { that.fanServiceZones.getCharacteristic(Characteristic.On).updateValue(false); } } //Start cleaning else { if (that.device.property("state") === 'zone-cleaning') { log.info('INFO | changedCleaning | ' + that.model + ' | Start zone cleaning'); that.zoneCleaning = true; if (that.zones) { that.fanServiceZones.getCharacteristic(Characteristic.On).updateValue(true); } that.fanService.getCharacteristic(Characteristic.On).updateValue(false); } else { if (that.zones) { that.fanServiceZones.getCharacteristic(Characteristic.On).updateValue(false); } that.fanService.getCharacteristic(Characteristic.On).updateValue(true); } } if (that.pause) { log.info('INFO | changedCleaning | ' + that.model + ' | Pause state has changed, is now ' + robotcleaning); that.pausepossible = robotcleaning; that.pauseService.getCharacteristic(Characteristic.On).updateValue(that.pausepossible); } } } this.changedSpeed = function(robotSpeed) { log.debug('DEBUG | changedSpeed | ' + that.model + ' | FanSpeed ' + robotSpeed + '%, the original homekit fan speed is step ' + that.speed); if (robotSpeed === 105) { that.speed = 1; that.fanService.getCharacteristic(Characteristic.RotationSpeed).updateValue(that.speed); if (that.zones) { that.fanServiceZones.getCharacteristic(Characteristic.RotationSpeed).updateValue(that.speed); } log.info('INFO | changedSpeed | ' + that.model + ' | Speed was changed to 105% (Mopping), set HomeKit to step ' + that.speed); return; } for (var i = 0; i < that.speedmodes.length; i++) { if (that.speedmodes[i] !== 105 && robotSpeed <= that.speedmodes[i]) { that.speed = i; that.fanService.getCharacteristic(Characteristic.RotationSpeed).updateValue(i); if (that.zones) { that.fanServiceZones.getCharacteristic(Characteristic.RotationSpeed).updateValue(i); } log.info('INFO | changedSpeed | ' + that.model + ' | Speed was changed to step ' + that.speed); return; } } } this.changedBattery = function(level) { log.info('INFO | changedBattery | ' + that.model + ' | BatteryLevel ' + level + '%'); that.batteryService.getCharacteristic(Characteristic.BatteryLevel).updateValue(level); that.batteryService.getCharacteristic(Characteristic.StatusLowBattery).updateValue((level < 20) ? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); } this.changedCharging = function(robotcharging) { log.debug('DEBUG | changedCharging | ' + that.model + ' | ChargingState ' + robotcharging); if (robotcharging !== that.charging) { log.info('INFO | changedCharging | ' + that.model + ' | Charging state is changed to ' + robotcharging); that.charging = robotcharging; that.batteryService.getCharacteristic(Characteristic.ChargingState).updateValue(that.charging ? Characteristic.ChargingState.CHARGING : Characteristic.ChargingState.NOT_CHARGING); if (that.dock) { that.dockService.getCharacteristic(Characteristic.OccupancyDetected).updateValue(that.charging); } //Changed from not charging to charging if (that.charging) { that.goingTo = false; that.zoneCleaning = false; that.cleaning = false; } } } that.getDevice(); } RoborockVacuum.prototype = { getDevice: function() { var that = this; var log = that.log; miio.device({ address: that.ip, token: that.token }).then(result => { if (result.matches('type:vaccuum')) { // INFO AT STARTUP if (that.startup) { log.info('INFO | getDevice | Connected to: %s', that.ip); log.info('INFO | getDevice | Model: ' + result.miioModel); log.info('INFO | getDevice | State: ' + result.property("state")); log.info('INFO | getDevice | FanSpeed: ' + result.property("fanSpeed")); log.info('INFO | getDevice | BatteryLevel: ' + result.property("batteryLevel")); // Serialnumber result.call("get_serial_number").then(serial => { serial = JSON.parse(JSON.stringify(serial)); // Convert in valid JSON. log.info('INFO | getDevice | Serialnumber: ' + serial[0].serial_number); }).catch(err => { log.error('ERROR | getDevice | get_serial_number | ' + err); }); // Firmwareversion result.call("miIO.info").then(firmware => { firmware = JSON.parse(JSON.stringify(firmware)); // Convert in valid JSON. log.info('INFO | getDevice | Firmwareversion: ' + firmware.fw_ver); }).catch(err => { log.error('ERROR | getDevice | miIO.info | ' + err); }); that.model = result.miioModel; that.startup = false; } // STATE result.state().then(state => { state = JSON.parse(JSON.stringify(state)); // Convert in valid JSON log.debug('DEBUG | getDevice | Received the initial state from the device: ' + JSON.stringify(state)); if (state.error !== undefined) { that.changedError(state.error); } log.debug('DEBUG | getDevice | Set the initial cleaning state to ' + state.cleaning); that.changedCleaning(state.cleaning); log.debug('DEBUG | getDevice | Set the initial charging state to ' + state.charging); that.changedCharging(state.charging); log.debug('DEBUG | getDevice | Set the initial battery level to ' + state.batteryLevel); that.changedBattery(state.batteryLevel); log.debug('DEBUG | getDevice | Set the initial fan speed to ' + state.fanSpeed); that.changedSpeed(state.fanSpeed); log.debug('DEBUG | getDevice | Registering event listeners'); result.on('thing:initialized', msg => { log.debug('DEBUG | getDevice | On thing:initialized'); }); result.on('thing:destroyed', msg => { log.error('ERROR | getDevice | on thing:destroyed'); }); result.on('errorChanged', error => { error = JSON.parse(JSON.stringify(error)); // Convert in valid JSON log.debug('DEBUG | getDevice on errorChanged ' + JSON.stringify(error)); //console.log(error) that.changedError(error); }); result.on('stateChanged', state => { state = JSON.parse(JSON.stringify(state)); // Convert in valid JSON log.debug('DEBUG | getDevice | on stateChanged ' + JSON.stringify(state)); if (state['key'] == "cleaning") { that.changedCleaning(state['value']) } if (state['key'] == "charging") { that.changedCharging(state['value']) } if (state['key'] == "fanSpeed") { that.changedSpeed(state['value']) } if (state['key'] == "batteryLevel") { that.changedBattery(state['value']) } }); //log.info('ROBOROCK start the timer to pull device state every minute!'); //IntervalID = setInterval(function() { // that.device.call('get_status').then(res => { // log.info('ROBOROCK get_status with result ' + JSON.stringify(res)); // }).catch(err => { // log.error('ROBOROCK get_status failed with error ' + err); // }); // }, 60000); }).catch(err => { log.error('ERROR | getDevice | result.state | ' + err) }) that.device = result; } else { log.error('ERROR | getDevice | The device is not a vacuum cleaner: '+ result); result.destroy(); } }).catch(err => { log.error('ERROR | getDevice | miio.device, next try in 2 minutes | ' + err); //result.destroy(); // If "destroy" no reconnect - timeout doesn't work. setTimeout(function() { that.getDevice() }, 120000); // No response from device over miio, wait 120 seconds for next try. }); }, checkDevice: function(functionName, callback) { var that = this; var log = that.log; if (!that.device) { log.error('ERROR | ' + functionName + ' | No vacuum cleaner is discovered.'); callback(new Error('No vacuum cleaner is discovered.')); return false; } return true; }, getCleaning: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getCleaning', callback)) { log.debug('DEBUG | getCleaning | Trying to poll the status.'); that.device.poll(false); log.info('INFO | getCleaning | ' + that.model + ' | Cleaning is ' + that.cleaning && !that.zoneCleaning + '.') callback(null, that.cleaning && !that.zoneCleaning); } }, setCleaning: function(state, callback) { var that = this; var log = that.log; log.debug('DEBUG | setCleaning | ' + that.model + ' | Cleaning is set to ' + state + '.'); changeCleaning('setCleaning', state, callback, false); }, changeCleaning(functionName, state, callback, isZoneCleaning) { if (that.checkDevice(functionName, callback)) { if (state) { if (that.charging) { log.info('INFO | ' + functionName + ' | ' + that.model + ' | Start cleaning with zones enabled = ' + isZoneCleaning); if (!isZoneCleaning) { that.device.activateCleaning().then(res => { log.debug('DEBUG | ' + functionName + ' | call device.activateCleaning succeeded'); }).catch(err => { log.warn('WARN | ' + functionName + ' | call device.activateCleaning failed with error ' + err); callback(new Error('Call device.activateCleaning failed with error ' + err)); return; }); } else { that.device.activateZoneClean(that.zonesWithRepeats).then(res => { log.debug('DEBUG | ' + functionName + ' | call device.activateZoneClean succeeded'); that.zoneCleaning = true; }).catch(err => { log.warn('WARN | ' + functionName + ' | call device.activateZoneClean failed with error ' + err); callback(new Error('Call device.activateZoneClean failed with error ' + err)); return; }); } } else { log.warn('WARN | ' + functionName + ' | ' + that.model + ' | Cannot start cleaning when the device is not in charging state.'); callback(new Error('Cannot start cleaning when the device is not in charging state.')); return; } } else { if (!that.charging) { log.info('INFO | ' + functionName + ' | ' + that.model + ' | Stop cleaning and go to charge.'); that.device.activateCharging().then(res => { log.debug('DEBUG | ' + functionName + ' | call device.activateCharging succeeded'); }).catch(err => { log.warn('DEBUG | ' + functionName + ' | call device.activateCharging failed with error ' + err); callback(new Error('Call device.activateCharging failed with error ' + err)); return; }); } } callback(); } }, getGotoTarget: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getGotoTarget', callback)) { log.info('INFO | getGotoTarget | ' + that.model + ' | Cleaning is ' + that.goingTo + '.') callback(null, that.goingTo); } }, setGotoTarget: function(state, callback) { var that = this; var log = that.log; log.debug('DEBUG | setGotoTarget | ' + that.model + ' | GotoTarget is set to ' + state + '.'); if (!that.checkDevice('setGotoTarget', callback)) { return; } if (state) { if (that.charging && that.target) { log.info('INFO | setGotoTarget | ' + that.model + ' | Start goto target.'); that.device.activateGoToTarget(that.target).then(res => { log.debug('DEBUG | setGotoTarget | call device.activateGoToTarget succeeded'); that.goingTo = true; }).catch(err => { log.warn('WARN | setGotoTarget | call device.activateGoToTarget failed with error ' + err); callback(new Error('Call device.activateGoToTarget failed with error ' + err)); return; }); } else { log.warn('WARN | setGotoTarget | ' + that.model + ' | Device is not in charging state or target not defined.'); callback(new Error('Device is not in charging state or target not defined.')); return; } } else { if (that.device.property("state") === 'waiting') { log.info('INFO | setGotoTarget | ' + that.model + ' | Go back to charge.'); that.device.activateCharging().then(res => { log.debug('DEBUG | setGotoTarget | call device.activateCharging succeeded'); }).catch(err => { log.warn('WARN | setGotoTarget | call device.activateCharging failed with error ' + err); callback(new Error('Call device.activateCharging failed with error ' + err)); return; }); } else { log.warn('WARN | setGotoTarget | ' + that.model + ' | Not able to return to dock because device is on the way to target.'); callback(new Error('Not able to return to dock because device is on the way to target.')); return; } } callback(); }, getZoneCleaning: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getZoneCleaning', callback)) { log.info('INFO | getZoneCleaning | ' + that.model + ' | Cleaning is ' + that.cleaning && that.zoneCleaning + '.') callback(null, that.cleaning && that.zoneCleaning); } }, setZoneCleaning: function(state, callback) { var that = this; var log = that.log; log.debug('DEBUG | setZoneCleaning | ' + that.model + ' | Cleaning is set to ' + state + '.'); changeCleaning('setZoneCleaning', state, callback, true); }, getSpeed: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getSpeed', callback)) { log.info('INFO | getSpeed | ' + that.model + ' | Fanspeed is ' + that.speed + '%.') callback(that.speed); } }, setSpeed: function(speed, callback) { var that = this; var log = that.log; log.info('INFO | setSpeed | ' + that.model + ' | Speed got %s% from HomeKit.', speed); if (!that.checkDevice('setSpeed', callback)) { return; } if (that.speed === speed) { callback(null); return; } if (speed < that.speedmodes.length && speed >= 0) { that.device.changeFanSpeed(parseInt(that.speedmodes[speed])).then(res => { log.debug('DEBUG | setSpeed | Call device.changeFanSpeed to ' + that.speedmiio + '% succeeded'); }).catch(err => { log.warn('WARN | setSpeed | Call device.changeFanSpeed failed with error ' + err); callback(new Error('Call device.changeFanSpeed failed with error ' + err)); return; }); } else { log.warn('WARN | setSpeed | ' + that.model + ' | Fan speed set to ' + speed + ' which is not supported.'); callback(new Error('Fan speed set to ' + speed + ' which is not supported.')); } //that.fanService.getCharacteristic(Characteristic.RotationSpeed).updateValue(that.speed); //if (that.zones) { // that.fanServiceZones.getCharacteristic(Characteristic.RotationSpeed).updateValue(that.speed); //} callback(null); }, getCharging: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getCharging', callback)) { log.debug('DEBUG | getCharging | ' + that.model + ' | Charging is ' + that.charging); callback(null, that.charging ? Characteristic.ChargingState.CHARGING : Characteristic.ChargingState.NOT_CHARGEABLE); } }, getBattery: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getBattery', callback)) { log.info('INFO | getBattery | ' + that.model + ' | Batterylevel is ' + that.device.property("batteryLevel") + '%.'); callback(null, that.device.property("batteryLevel")); } }, getBatteryLow: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getBatteryLow', callback)) { callback(null, (that.device.property("batteryLevel") < 20) ? Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL); } }, getPausestate: function(callback) { var that = this; var log = that.log; if (that.checkDevice('getPausestate', callback)) { log.info('INFO | getPausestate | ' + that.model + ' | Pause possible is ' + that.pausepossible + '.') callback(null, that.pausepossible); } }, setPausestate: function(state, callback) { var that = this; var log = that.log; log.debug('DEBUG | setPausestate | ' + that.model + ' | Pause set it to ' + state + '.'); if (!that.checkDevice('setPausestate', callback)) { return; } if (!that.cleaning) { log.error('ERROR | setPausestate | Not possible to pause because the device is not in cleaning state.'); callback(new Error('ERR setPausestate | Not possible to pause because the device is not in cleaning state.')); return; } if (state && !that.pausepossible) { log.info('INFO | setPausestate | ' + that.model + ' | Resume cleaning.'); if (that.zoneCleaning) { that.device.activateZoneClean(that.zonesWithRepeats).then(res => { log.debug('DEBUG | setPausestate | call device.activateZoneClean succeeded'); that.zoneCleaning = true; }).catch(err => { log.warn('WARN | setPausestate | call device.activateZoneClean failed with error ' + err); callback(new Error('Call device.activateZoneClean failed with error ' + err)); return; }); } else { that.device.activateCleaning().then(res => { log.debug('DEBUG | setPausestate | call device.activateCleaning succeeded'); that.pausepossible = true; }).catch(err => { log.error('ERROR | setPausestate | call device.activateCleaning failed with error ' + err); callback(new Error('Call device.activateCleaning failed with error ' + err)); return; }); } } else if (!state && that.pausepossible) { log.info('INFO | setPausestate | ' + that.model + ' | Pause.'); that.device.pause().then(res => { log.debug('DEBUG | setPausestate | Call device.pause succeeded'); that.pausepossible = false; }).catch(err => { log.error('ERROR | setPausestate | Call device.pause failed with error ' + err); callback(new Error('Call device.pause failed with error ' + err)); return; }); } else { log.warn('WARN | setPausestate | Try to set pause to ' + state + ' when in state ' + that.pausepossible); } callback(); }, getServices: function() { var that = this; return that.services; }, // CONSUMABLE / CARE getCareSensors: function(callback) { // 30h = sensor_dirty_time var that = this; var log = that.log; if (that.checkDevice('getCareSensors', callback)) { lifetime = 108000; lifetimepercent = that.device.property("sensorDirtyTime") / lifetime * 100; log.info('INFO | getCareSensors | ' + that.model + ' | Sensors dirtytime are ' + that.device.property("sensorDirtyTime") + ' seconds / ' + lifetimepercent.toFixed(2) + '%.') callback(null, lifetimepercent); } }, getCareFilter: function(callback) { // 150h = filter_work_time var that = this; var log = that.log; if (that.checkDevice('getCareFilter', callback)) { lifetime = 540000; lifetimepercent = that.device.property("filterWorkTime") / lifetime * 100; log.info('INFO | getCareFilter | ' + that.model + ' | Filter worktime is ' + that.device.property("filterWorkTime") + ' seconds / ' + lifetimepercent.toFixed(2) + '%.') callback(null, lifetimepercent); } }, getCareSideBrush: function(callback) { // 200h = side_brush_work_time var that = this; var log = that.log; if (that.checkDevice('getCareSideBrush', callback)) { lifetime = 720000; lifetimepercent = that.device.property("sideBrushWorkTime") / lifetime * 100; log.info('INFO | getCareSideBrush | ' + that.model + ' | Sidebrush worktime is ' + that.device.property("sideBrushWorkTime") + ' seconds / ' + lifetimepercent.toFixed(2) + '%.') callback(null, lifetimepercent); } }, getCareMainBrush: function(callback) { // 300h = main_brush_work_time var that = this; var log = that.log; if (checkDevice('getCareMainBrush', callback)) { lifetime = 1080000; lifetimepercent = that.device.property("mainBrushWorkTime") / lifetime * 100; log.info('INFO | getCareMainBrush | ' + that.model + ' | Mainbrush worktime is ' + that.device.property("mainBrushWorkTime") + ' seconds / ' + lifetimepercent.toFixed(2) + '%.') callback(null, lifetimepercent); } }, };