diff --git a/accessories/neatoVacuumRobot.js b/accessories/neatoVacuumRobot.js deleted file mode 100644 index 2c3908a..0000000 --- a/accessories/neatoVacuumRobot.js +++ /dev/null @@ -1,614 +0,0 @@ -const debug = require('debug')('homebridge-neato'); -const colors = require('colors'); - -const CustomUUID = { - SpotCleanWidth: 'A7889A9A-2F27-4293-BEF8-3FE805B36F4E', - SpotCleanHeight: 'CA282DB2-62BF-4325-A1BE-F8BB5478781A', - SpotCleanRepeat: '1E79C603-63B8-4E6A-9CE1-D31D67981831' -}; - -let Service, - Characteristic, - SpotWidthCharacteristic, - SpotHeightCharacteristic, - SpotRepeatCharacteristic; - -module.exports = function (_Service, _Characteristic) -{ - Service = _Service; - Characteristic = _Characteristic; - SpotWidthCharacteristic = require('../characteristics/spotWidth')(Characteristic, CustomUUID); - SpotHeightCharacteristic = require('../characteristics/spotHeight')(Characteristic, CustomUUID); - SpotRepeatCharacteristic = require('../characteristics/spotRepeat')(Characteristic, CustomUUID); - - return NeatoVacuumRobotAccessory; -}; - -function NeatoVacuumRobotAccessory(platform, robotObject) -{ - this.platform = platform; - this.log = platform.log; - this.refresh = platform.refresh; - this.hiddenServices = platform.hiddenServices; - this.nextRoom = platform.nextRoom; - - this.robotObject = robotObject; - this.robot = robotObject.device; - this.meta = robotObject.meta; - this.spotPlusFeatures = ((typeof robotObject.availableServices.spotCleaning !== 'undefined') && robotObject.availableServices.spotCleaning.includes("basic")); - this.boundary = (typeof robotObject.boundary === 'undefined') ? null : robotObject.boundary; - - if (this.boundary == null) - { - this.name = this.robot.name; - } - else - { - // if boundary name already exists - if (platform.boundaryNames.includes(this.boundary.name)) - { - let lastChar = this.boundary.name.slice(-1); - // boundary name already contains a count number - if (!isNaN(lastChar)) - { - // Increment existing count number - this.boundary.name = this.boundary.name.slice(0, -1) + (parseInt(lastChar) + 1); - } - else - { - // Add a new count number - this.boundary.name = this.boundary.name + " 2"; - } - } - platform.boundaryNames.push(this.boundary.name); - this.name = this.robot.name + ' - ' + this.boundary.name; - } - - this.batteryService = new Service.BatteryService("Battery", "battery"); - - if (this.boundary == null) - { - this.cleanService = new Service.Switch(this.name + " Clean", "clean"); - this.goToDockService = new Service.Switch(this.name + " Go to Dock", "goToDock"); - this.dockStateService = new Service.OccupancySensor(this.name + " Dock", "dockState"); - this.ecoService = new Service.Switch(this.name + " Eco Mode", "eco"); - this.noGoLinesService = new Service.Switch(this.name + " NoGo Lines", "noGoLines"); - this.extraCareService = new Service.Switch(this.name + " Extra Care", "extraCare"); - this.scheduleService = new Service.Switch(this.name + " Schedule", "schedule"); - this.findMeService = new Service.Switch(this.name + " Find Me", "findMe"); - - this.spotCleanService = new Service.Switch(this.name + " Clean Spot", "cleanSpot"); - this.spotCleanService.addCharacteristic(SpotRepeatCharacteristic); - if (this.spotPlusFeatures) - { - this.spotCleanService.addCharacteristic(SpotWidthCharacteristic); - this.spotCleanService.addCharacteristic(SpotHeightCharacteristic); - } - } - else - { - const splitName = this.boundary.name.split(' '); - let serviceName = "Clean the " + this.boundary.name; - if (splitName.length >= 2 && splitName[splitName.length - 2].match(/[']s$/g)) - { - serviceName = "Clean " + this.boundary.name; - } - this.cleanService = new Service.Switch(serviceName, "cleanBoundary:" + this.boundary.id); - } - - this.log("Added cleaning device named: " + this.name); -} - -NeatoVacuumRobotAccessory.prototype = { - identify: function (callback) - { - this.robot.getState((error, result) => - { - if (error) - { - this.log.error("Error getting robot information: " + error + ": " + result); - } - else - { - this.log("### Robot information ###"); - this.log(result); - } - callback(); - }); - }, - - getServices: function () - { - this.informationService = new Service.AccessoryInformation(); - this.informationService - .setCharacteristic(Characteristic.Manufacturer, "Neato Robotics") - .setCharacteristic(Characteristic.Model, this.meta.modelName) - .setCharacteristic(Characteristic.SerialNumber, this.robot._serial) - .setCharacteristic(Characteristic.FirmwareRevision, this.meta.firmware) - .setCharacteristic(Characteristic.Name, this.robot.name + (this.boundary == null ? '' : ' - ' + this.boundary.name)); - - this.cleanService.getCharacteristic(Characteristic.On).on('set', this.setClean.bind(this)); - this.cleanService.getCharacteristic(Characteristic.On).on('get', this.getClean.bind(this)); - - this.services = [this.informationService, this.cleanService]; - - if (this.boundary == null) - { - this.batteryService.getCharacteristic(Characteristic.BatteryLevel).on('get', this.getBatteryLevel.bind(this)); - this.batteryService.getCharacteristic(Characteristic.ChargingState).on('get', this.getBatteryChargingState.bind(this)); - this.services.push(this.batteryService); - - this.goToDockService.getCharacteristic(Characteristic.On).on('set', this.setGoToDock.bind(this)); - this.goToDockService.getCharacteristic(Characteristic.On).on('get', this.getGoToDock.bind(this)); - - this.dockStateService.getCharacteristic(Characteristic.OccupancyDetected).on('get', this.getDock.bind(this)); - - this.ecoService.getCharacteristic(Characteristic.On).on('set', this.setEco.bind(this)); - this.ecoService.getCharacteristic(Characteristic.On).on('get', this.getEco.bind(this)); - - this.noGoLinesService.getCharacteristic(Characteristic.On).on('set', this.setNoGoLines.bind(this)); - this.noGoLinesService.getCharacteristic(Characteristic.On).on('get', this.getNoGoLines.bind(this)); - - this.extraCareService.getCharacteristic(Characteristic.On).on('set', this.setExtraCare.bind(this)); - this.extraCareService.getCharacteristic(Characteristic.On).on('get', this.getExtraCare.bind(this)); - - this.scheduleService.getCharacteristic(Characteristic.On).on('set', this.setSchedule.bind(this)); - this.scheduleService.getCharacteristic(Characteristic.On).on('get', this.getSchedule.bind(this)); - - this.findMeService.getCharacteristic(Characteristic.On).on('set', this.setFindMe.bind(this)); - this.findMeService.getCharacteristic(Characteristic.On).on('get', this.getFindMe.bind(this)); - - this.spotCleanService.getCharacteristic(Characteristic.On).on('set', this.setSpotClean.bind(this)); - this.spotCleanService.getCharacteristic(Characteristic.On).on('get', this.getSpotClean.bind(this)); - this.spotCleanService.getCharacteristic(SpotRepeatCharacteristic).on('set', this.setSpotRepeat.bind(this)); - this.spotCleanService.getCharacteristic(SpotRepeatCharacteristic).on('get', this.getSpotRepeat.bind(this)); - - if (this.spotPlusFeatures) - { - this.spotCleanService.getCharacteristic(SpotWidthCharacteristic).on('set', this.setSpotWidth.bind(this)); - this.spotCleanService.getCharacteristic(SpotWidthCharacteristic).on('get', this.getSpotWidth.bind(this)); - this.spotCleanService.getCharacteristic(SpotHeightCharacteristic).on('set', this.setSpotHeight.bind(this)); - this.spotCleanService.getCharacteristic(SpotHeightCharacteristic).on('get', this.getSpotHeight.bind(this)); - } - - if (this.hiddenServices.indexOf('spot') === -1) - { - this.services.push(this.spotCleanService); - } - - // Add optional services - if (this.hiddenServices.indexOf('dock') === -1) - this.services.push(this.goToDockService); - if (this.hiddenServices.indexOf('dockstate') === -1) - this.services.push(this.dockStateService); - if (this.hiddenServices.indexOf('eco') === -1) - this.services.push(this.ecoService); - if (this.hiddenServices.indexOf('nogolines') === -1) - this.services.push(this.noGoLinesService); - if (this.hiddenServices.indexOf('extracare') === -1) - this.services.push(this.extraCareService); - if (this.hiddenServices.indexOf('schedule') === -1) - this.services.push(this.scheduleService); - if (this.hiddenServices.indexOf('find') === -1) - this.services.push(this.findMeService); - } - - return this.services; - }, - - - getClean: function (callback) - { - this.platform.updateRobot(this.robot._serial, (error, result) => - { - let cleaning; - if (this.boundary == null) - { - cleaning = this.robot.canPause; - } - else - { - cleaning = this.robot.canPause && (this.robot.cleaningBoundaryId === this.boundary.id) - } - - debug(this.name + ": Cleaning is " + (cleaning ? 'ON'.brightGreen : 'OFF'.red)); - callback(false, cleaning); - }); - }, - - setClean: function (on, callback) - { - - }, - - clean: function (callback, spot) - { - // Start automatic update while cleaning - if (this.refresh === 'auto') - { - setTimeout(() => - { - this.platform.updateRobotTimer(this.robot._serial); - }, 60 * 1000); - } - - let eco = this.robotObject.mainAccessory.ecoService.getCharacteristic(Characteristic.On).value; - let extraCare = this.robotObject.mainAccessory.extraCareService.getCharacteristic(Characteristic.On).value; - let nogoLines = this.robotObject.mainAccessory.noGoLinesService.getCharacteristic(Characteristic.On).value; - let room = (this.boundary == null) ? '' : this.boundary.name; - debug(this.name + ": ## Start cleaning (" + (room !== '' ? room + " " : '') + "eco: " + eco + ", extraCare: " + extraCare + ", nogoLines: " + nogoLines + ", spot: " + JSON.stringify(spot) + ")"); - - // Normal cleaning - if (this.boundary == null && (typeof spot === 'undefined')) - { - this.robot.startCleaning(eco, extraCare ? 2 : 1, nogoLines, (error, result) => - { - if (error) - { - this.log.error("Cannot start cleaning. " + error + ": " + JSON.stringify(result)); - } - callback(error); - }); - } - // Room cleaning - else if (room !== '') - { - this.robot.startCleaningBoundary(eco, extraCare, this.boundary.id, (error, result) => - { - if (error) - { - this.log.error("Cannot start room cleaning. " + error + ": " + JSON.stringify(result)); - } - callback(error); - }); - } - // Spot cleaning - else - { - this.robot.startSpotCleaning(eco, spot.width, spot.height, spot.repeat, extraCare ? 2 : 1, (error, result) => - { - if (error) - { - this.log.error("Cannot start spot cleaning. " + error + ": " + JSON.stringify(result)); - } - callback(error); - }); - } - }, - - getGoToDock: function (callback) - { - callback(false, false); - }, - - setGoToDock: function (on, callback) - { - this.platform.updateRobot(this.robot._serial, (error, result) => - { - if (on) - { - if (this.robot.canPause) - { - debug(this.name + ": ## Pause cleaning to go to dock"); - this.robot.pauseCleaning((error, result) => - { - setTimeout(() => - { - debug(this.name + ": ## Go to dock"); - this.robot.sendToBase(() => - { - callback(); - }); - }, 1000); - }); - } - else if (this.robot.canGoToBase) - { - debug(this.name + ": ## Go to dock"); - this.robot.sendToBase(() => - { - callback(); - }); - } - else - { - this.log.warn(this.name + ": Can't go to dock at the moment"); - callback(); - } - } - else - { - callback(); - } - }); - }, - - getEco: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Eco Mode is " + (this.robot.eco ? 'ON'.brightGreen : 'OFF'.red)); - callback(false, this.robot.eco); - }); - }, - - setEco: function (on, callback) - { - this.robot.eco = on; - debug(this.name + ": " + (on ? "Enabled ".red : "Disabled".red) + " Eco Mode "); - callback(); - }, - - getNoGoLines: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": NoGoLine is " + (this.robot.eco ? 'ON'.brightGreen : 'OFF'.red)); - callback(false, this.robot.noGoLines ? 1 : 0); - }); - }, - - setNoGoLines: function (on, callback) - { - this.robot.noGoLines = on; - debug(this.name + ": " + (on ? "Enabled ".brightGreen : "Disabled".red) + " NoGoLine "); - callback(); - }, - - getExtraCare: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Care Nav is " + (this.robot.navigationMode === 2 ? 'ON'.brightGreen : 'OFF'.red)); - callback(false, this.robot.navigationMode === 2 ? 1 : 0); - }); - }, - - setExtraCare: function (on, callback) - { - this.robot.navigationMode = on ? 2 : 1; - debug(this.name + ": " + (on ? "Enabled ".brightGreen : "Disabled".red) + " Care Nav "); - callback(); - }, - - getSchedule: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Schedule is " + (this.robot.eco ? 'ON'.brightGreen : 'OFF'.red)); - callback(false, this.robot.isScheduleEnabled); - }); - }, - - setSchedule: function (on, callback) - { - this.platform.updateRobot(this.robot._serial, (error, result) => - { - if (on) - { - debug(this.name + ": " + "Enabled".brightGreen + " Schedule"); - this.robot.enableSchedule((error) => - { - callback(error); - }); - } - else - { - debug(this.name + ": " + "Disabled".red + " Schedule"); - this.robot.disableSchedule((error) => - { - callback(error); - }); - } - }); - }, - - getFindMe: function (callback) - { - callback(false, false); - }, - - setFindMe: function (on, callback) - { - if (on) - { - debug(this.name + ": ## Find me"); - setTimeout(() => - { - this.findMeService.setCharacteristic(Characteristic.On, false); - }, 1000); - - this.robot.findMe((error) => - { - callback(error); - }); - } - }, - - getSpotClean: function (callback) - { - callback(false, this.spotCleanService.getCharacteristic(Characteristic.On).value); - }, - - setSpotClean: function (on, callback) - { - let spot = { - width: this.spotPlusFeatures ? this.spotCleanService.getCharacteristic(SpotWidthCharacteristic).value : null, - height: this.spotPlusFeatures ? this.spotCleanService.getCharacteristic(SpotHeightCharacteristic).value : null, - repeat: this.spotCleanService.getCharacteristic(SpotRepeatCharacteristic).value - }; - - this.platform.updateRobot(this.robot._serial, (error, result) => - { - // Start - if (on) - { - // Resume cleaning - if (this.robot.canResume) - { - debug(this.name + ": ## Resume (spot) cleaning"); - this.robot.resumeCleaning(callback); - } - // Start cleaning - else if (this.robot.canStart) - { - this.clean(callback, spot); - } - // Cannot start - else - { - debug(this.name + ": Cannot start spot cleaning, maybe already cleaning"); - callback(); - } - } - // Stop - else - { - if (this.robot.canPause) - { - debug(this.name + ": ## Pause cleaning"); - this.robot.pauseCleaning((error) => - { - callback(error); - }); - } - else - { - debug(this.name + ": Already paused"); - callback(); - } - } - }); - }, - - getSpotWidth: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Spot width is " + this.robot.spotWidth + "cm"); - callback(false, this.robot.spotWidth); - }); - }, - - setSpotWidth: function (width, callback) - { - this.robot.spotWidth = width; - debug(this.name + ": Set spot width to " + width + "cm"); - callback(); - }, - - getSpotHeight: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Spot height is " + this.robot.spotHeight + "cm"); - callback(false, this.robot.spotHeight); - }); - }, - - setSpotHeight: function (height, callback) - { - this.robot.spotHeight = height; - debug(this.name + ": Set spot height to " + height + "cm"); - callback(); - }, - - getSpotRepeat: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Spot repeat is " + (this.robot.spotRepeat ? 'ON'.brightGreen : 'OFF'.red)); - callback(false, this.robot.spotRepeat); - }); - }, - - setSpotRepeat: function (on, callback) - { - this.robot.spotRepeat = on; - debug(this.name + ": " + (on ? "Enabled ".brightGreen : "Disabled".red) + " Spot repeat"); - callback(); - }, - - getDock: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": The Dock is " + (this.robot.isDocked ? "OCCUPIED".brightGreen : "NOT OCCUPIED".red)); - callback(false, this.robot.isDocked ? 1 : 0); - }); - }, - - getBatteryLevel: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Battery is " + this.robot.charge + "%"); - callback(false, this.robot.charge); - }); - }, - - getBatteryChargingState: function (callback) - { - this.platform.updateRobot(this.robot._serial, () => - { - debug(this.name + ": Battery is " + (this.robot.isCharging ? "CHARGING".brightGreen : "NOT CHARGING".red)); - callback(false, this.robot.isCharging); - }); - }, - - updated: function () - { - if (this.boundary == null) - { - // only update these values if the state is different from the current one, otherwise we might accidentally start an action - if (this.cleanService.getCharacteristic(Characteristic.On).value !== this.robot.canPause) - { - this.cleanService.setCharacteristic(Characteristic.On, this.robot.canPause); - } - - // dock switch is on (dock not seen before) and dock has just been seen -> turn switch off - if (this.goToDockService.getCharacteristic(Characteristic.On).value == true && this.robot.dockHasBeenSeen) - { - this.goToDockService.setCharacteristic(Characteristic.On, false); - } - - if (this.scheduleService.getCharacteristic(Characteristic.On).value !== this.robot.isScheduleEnabled) - { - this.scheduleService.setCharacteristic(Characteristic.On, this.robot.isScheduleEnabled); - } - - // no commands here, values can be updated without problems - this.dockStateService.setCharacteristic(Characteristic.OccupancyDetected, this.robot.isDocked ? 1 : 0); - - this.ecoService.setCharacteristic(Characteristic.On, this.robot.eco); - this.noGoLinesService.setCharacteristic(Characteristic.On, this.robot.noGoLines); - this.extraCareService.setCharacteristic(Characteristic.On, this.robot.navigationMode == 2 ? true : false); - - this.spotCleanService.setCharacteristic(SpotRepeatCharacteristic, this.robot.spotRepeat); - - if (this.spotPlusFeatures) - { - let widthProps = this.spotCleanService.getCharacteristic(SpotWidthCharacteristic).props; - let heightProps = this.spotCleanService.getCharacteristic(SpotHeightCharacteristic).props; - - this.spotCleanService.setCharacteristic(SpotWidthCharacteristic, - this.robot.spotWidth >= widthProps.minValue && this.robot.spotWidth <= widthProps.maxValue ? this.robot.spotWidth : widthProps.minValue); - this.spotCleanService.setCharacteristic(SpotHeightCharacteristic, - this.robot.spotHeight >= heightProps.minValue && this.robot.spotHeight <= heightProps.maxValue ? this.robot.spotHeight : heightProps.minValue); - } - } - - this.batteryService.setCharacteristic(Characteristic.BatteryLevel, this.robot.charge); - this.batteryService.setCharacteristic(Characteristic.ChargingState, this.robot.isCharging); - - // Robot has a next room to clean in queue - if (this.nextRoom != null && this.robot.isDocked) - { - this.clean((error, result) => - { - this.nextRoom = null; - debug("## Starting cleaning of next room"); - }); - } - } -}; \ No newline at end of file diff --git a/characteristics/spotHeight.js b/characteristics/spotHeight.js deleted file mode 100644 index e609595..0000000 --- a/characteristics/spotHeight.js +++ /dev/null @@ -1,21 +0,0 @@ -const inherits = require('util').inherits; - -module.exports = function (Characteristic, CustomUUID) -{ - let SpotHeight = function () - { - Characteristic.call(this, 'Spot ↕', CustomUUID.SpotCleanHeight); - this.setProps({ - format: Characteristic.Formats.INT, - unit: 'cm', - maxValue: 400, - minValue: 100, - minStep: 50, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] - }); - this.value = this.getDefaultValue(); - }; - inherits(SpotHeight, Characteristic); - - return SpotHeight; -}; \ No newline at end of file diff --git a/characteristics/spotRepeat.js b/characteristics/spotRepeat.js deleted file mode 100644 index 8f7d72d..0000000 --- a/characteristics/spotRepeat.js +++ /dev/null @@ -1,17 +0,0 @@ -const inherits = require('util').inherits; - -module.exports = function (Characteristic, CustomUUID) -{ - let SpotRepeat = function () - { - Characteristic.call(this, 'Spot 2x', CustomUUID.SpotCleanRepeat); - this.setProps({ - format: Characteristic.Formats.BOOL, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] - }); - this.value = this.getDefaultValue(); - }; - inherits(SpotRepeat, Characteristic); - - return SpotRepeat; -}; \ No newline at end of file diff --git a/characteristics/spotWidth.js b/characteristics/spotWidth.js deleted file mode 100644 index e3ed9cf..0000000 --- a/characteristics/spotWidth.js +++ /dev/null @@ -1,21 +0,0 @@ -const inherits = require('util').inherits; - -module.exports = function (Characteristic, CustomUUID) -{ - let SpotWidth = function () - { - Characteristic.call(this, 'Spot ↔', CustomUUID.SpotCleanWidth); - this.setProps({ - format: Characteristic.Formats.INT, - unit: 'cm', - maxValue: 400, - minValue: 100, - minStep: 50, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] - }); - this.value = this.getDefaultValue(); - }; - inherits(SpotWidth, Characteristic); - - return SpotWidth; -}; \ No newline at end of file diff --git a/config.schema.json b/config.schema.json index 290f674..15cb50e 100644 --- a/config.schema.json +++ b/config.schema.json @@ -1,23 +1,93 @@ { - "pluginAlias": "NeatoVacuumRobot", - "pluginType": "platform", - "headerDisplay": "For Advanced settings like Refresh time interval or Disabled switches/sensors. [Check Here](https://github.com/naofireblade/homebridge-neato#readme)", - "schema": { - "type": "object", - "properties": { - "email": { - "title": "email", + "pluginAlias": "NeatoVacuumRobot", + "pluginType": "platform", + "singular": true, + "headerDisplay": "", + "schema": { + "type": "object", + "properties": { + "email": { + "title": "E-Mail", + "type": "string", + "required": true, + "format": "email" + }, + "password": { + "title": "Password", + "type": "string", + "required": true + }, + "prefix": { + "title": "Prefix robot name", + "description": "Display the name of the robot in front of every service.", + "type": "boolean", + "default": false + }, + "backgroundUpdate": { + "title": "Background update", + "description": "Interval for background updates while the robot is not cleaning (in minutes). During cleaning, the robot will automatically update at a faster rate.", + "type": "integer", + "minimum": 1, + "default": 30 + }, + "services": { + "type": "array", + "items": { "type": "string", - "required": true, - "format": "email", - "description": "Your Email Address" + "enum": [ + "Clean house", + "Clean spot", + "Go to dock", + "Find me", + "Schedule", + "Eco", + "Nogo lines", + "Extra care", + "Docked sensor", + "Bin full sensor" + ] }, - "password": { - "title": "password", - "type": "string", - "required": true, - "description": "Your Password" - } + "uniqueItems": true } } + }, + "layout": [ + { + "type": "help", + "helpvalue": "