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
JavaScript
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);
}
},
};