33 Commits

Author SHA1 Message Date
Arne
4a97487400 Added contributor and bumped version to v0.6.0 2019-07-14 23:35:09 +02:00
Arne
5ea9dde49c Merge pull request #28 from az0uz/feature/zone_cleaning
Support for zone cleaning
2019-07-14 23:32:43 +02:00
Arne
8ef24c9d40 Update package.json 2019-07-10 10:27:11 +02:00
Antoine de Maleprade
979dc40ccf fixed uuid reset when restarting homebridge, removed logs 2019-05-06 20:11:04 -07:00
Antoine de Maleprade
7d824ee0b9 Working zone cleaning, implemented multiple accesories to have a room per switch in homekit 2019-04-28 17:35:49 -07:00
Antoine de Maleprade
b87e49e12f fix: zone services discovery 2019-04-27 22:52:49 -07:00
Antoine de Maleprade
afe7d690ef Added zone cleaning 2019-04-27 22:06:07 -07:00
Arne
442b91c347 Versionbump to v0.5.2 2019-04-09 12:46:08 +02:00
Arne
55020c005b Merge pull request #26 from btutal/master
Add Schema for Config
2019-04-09 12:43:31 +02:00
Berkay
7c72aabb25 Add Schema for Config
Add schema file for homebridge-config-ui-x and similar plugins
2019-04-08 22:26:30 +02:00
Arne
e1754e02ed Fixed console log in node-botvac 2018-11-17 13:27:33 +01:00
Arne
0b864eb229 Updated readme 2018-11-14 22:42:38 +01:00
Arne
1d1fa121a4 Updated readme 2018-11-14 18:24:52 +01:00
Arne
6c6bb1c204 Updated readme and changelog 2018-11-14 18:22:27 +01:00
Arne
577e62ea32 Improved refresh interval 2018-11-13 21:47:39 +01:00
Arne
fbec31602f NoGo Lines and options sync
ADDED
- NoGo lines button
- Extra care navigation button
- Syncing cleaning options from last run

CHANGED
- Goto dock button is now always off
- Better error handling
- More detailed debug messages
- Updated node-botvac dependency to 0.1.6

REMOVED
- Extra care navigation option parameter (is now a button)
2018-11-11 15:53:50 +01:00
naofireblade
42fa0399f8 Version 0.4.7
* Fixed an exception when no robot is associated with the account
2018-03-26 19:14:54 +02:00
Arne
0de549dd41 Merge pull request #12 from ghulands/fix_no_robots
Set an empty array if there are no robots on the account
2018-03-25 22:01:32 +02:00
Greg Hulands
7fef07df0a Set an empty array if there are no robots on the account 2018-03-24 22:54:12 -07:00
Arne
9e9dd80547 Added badges 2018-02-08 12:14:48 +01:00
Arne
b7ec93953e Updated list of supported robots 2018-01-11 08:01:18 +01:00
naofireblade
ad41c1679d Version 0.4.6
* Added error log while refreshing robot state
* Fixed a rare bug where the robot stops after some seconds of cleaning
2017-12-10 13:14:12 +01:00
naofireblade
89f6f233a5 Added errorlog while refreshing robot state 2017-10-15 19:34:02 +02:00
naofireblade
88f217e2b1 Version 0.4.5
* Fixed compatibility with homebridge 0.4.23 (occupancy sensor not
working)
2017-09-04 00:13:44 +02:00
naofireblade
2fec762498 Version 0.4.4
* Fixed config parameter to disable switches/sensors not optional
2017-07-25 08:54:52 +02:00
naofireblade
857af55e99 Version 0.4.3
* Fixed config parameter to disable switches/sensors not optional
2017-07-25 08:52:17 +02:00
naofireblade
20e0a9b909 Version 0.4.2
* Added config parameter to disable switches/sensors
2017-07-24 19:52:32 +02:00
Arne
afdff765b0 Wording 2017-06-07 10:51:14 +02:00
Arne
dcef6653ff Wording 2017-06-07 10:50:44 +02:00
Arne
82bf19c548 Wording 2017-06-07 10:48:46 +02:00
Arne
1084bff0ee Wording 2017-06-07 10:48:11 +02:00
Arne
5aa66835dd Wording 2017-06-07 10:47:01 +02:00
naofireblade
08ef90f7b0 Version 0.4.1
* Added config parameter for extraCareNavigation
2017-06-06 17:25:02 +02:00
5 changed files with 454 additions and 148 deletions

View File

@@ -37,4 +37,49 @@
* Added support for multiple robots
* Added log output when user requests accessory identify
* Changed plugin to platform instead of single accessory
* Removed parameter name from config
* Removed parameter name from config
## 0.4.1
* Added config parameter for extraCareNavigation
## 0.4.2
* Added config parameter to disable switches/sensors
## 0.4.4
* Fixed config parameter to disable switches/sensors not optional
## 0.4.5
* Fixed compatibility with homebridge 0.4.23 (occupancy sensor not working)
## 0.4.6
* Added error log while refreshing robot state
* Fixed a rare bug where the robot stops after some seconds of cleaning
## 0.4.7
* Fixed an exception when no robot is associated with the account
## 0.5.0
* Added noGo lines button
* Added extra care navigation button
* Added syncing cleaning options from last run
* Added option to disable background state update completely
* Changed goto dock button is now always off
* Changed error handling
* Changed debug messages
* Updated node-botvac dependency to 0.1.6
* Removed extra care navigation option parameter (is now a button)
## 0.5.1
* Updated node-botvac dependency to 0.1.7
## 0.5.2
* Added schema file for use with homebridge-config-ui-x

View File

@@ -1,38 +1,56 @@
# homebridge-neato
[![npm](https://img.shields.io/npm/v/homebridge-neato.svg?style=flat-square)](https://www.npmjs.com/package/homebridge-neato)
[![npm](https://img.shields.io/npm/dt/homebridge-neato.svg?style=flat-square)](https://www.npmjs.com/package/homebridge-neato)
[![GitHub last commit](https://img.shields.io/github/last-commit/naofireblade/homebridge-neato.svg?style=flat-square)](https://github.com/naofireblade/homebridge-neato)
This is a plugin for [homebridge](https://github.com/nfarina/homebridge) to control your [Neato](https://www.neatorobotics.com/) vacuum robot. You can download it via [npm](https://www.npmjs.com/package/homebridge-neato).
Feel free to leave any feedback [here](https://github.com/naofireblade/homebridge-neato/issues).
If you update from a previous version you have to adapt your config.
# Features
## Features
- Start and pause cleaning
- Return to dock\*
- Enable and disable schedule
- Enable and disable eco mode
- Return to dock
- Scheduling
- Eco mode
- Extra care navigation
- Nogo lines
- Zone cleaning
- Get battery info
- Get dock info
- Periodic refresh of robot state
- Support for multiple robots
\* Available after some seconds of cleaning.
**Hint:** To control the robot with your own commands just set up a scene with the name of your choice.
# Installation
## Installation
1. Install homebridge using: `npm install -g homebridge`
2. Install this plugin using: `npm install -g homebridge-neato`
3. If you don't have a Neato account yet create one [here](https://www.neatorobotics.com/create-account/).
4. Update your configuration file. See the sample below.
### Configuration
## Configuration
Add the following information to your config file. Change the values for name, email and password.
Add the following information to your config file. Change the values for email and password.
The parameter **refresh** is optional (default 0=off) and adjusts in what interval (seconds) changes of the robot state will be pushed to homekit. The minimum refresh time is 60 seconds. You need this only when you set up rules based on the robot state and start him outside of homekit (e.g. with the Neato app).
### Simple
```json
"platforms": [
{
"platform": "NeatoVacuumRobot",
"email": "YourEmail",
"password": "YourPassword"
}
]
```
### Advanced
The following config contains advanced optional settings.
The parameter **refresh** sets an interval in seconds that is used to update the robot state in the background. This is only required for automations based on the robot state. The default value is `auto` which means that the update is automatically enabled while cleaning and disabled while not cleaning. You can set a value in seconds e.g. `120` to enable background updates even when the robot is not cleaning. You can also disable background updates completely by setting the value `0`. This might be required if you experience timeouts in the app because you have other home automation apps that are connected to your robot.
The parameter **disabled** accepts a list of switches/sensors that can be disabled in the neato homekit plugin (e.g. dock, dockstate, eco, schedule).
```json
"platforms": [
@@ -40,14 +58,23 @@ The parameter **refresh** is optional (default 0=off) and adjusts in what interv
"platform": "NeatoVacuumRobot",
"email": "YourEmail",
"password": "YourPassword",
"refresh": "0"
"refresh": "120",
"disabled": ["dock", "dockstate", "eco", "nogolines", "extracare", "schedule"]
}
]
```
# Tested robots
## Tested robots
- BotVac Connected (Firmware 2.2.0)
- BotVac D5 Connected
- BotVac D3 Connected
- BotVac D5 Connected (Firmware 4.0.0, 4.3.0)
- BotVac D7 Connected
If you have another connected neato robot, please [tell me](https://github.com/naofireblade/homebridge-neato/issues) about your experience with this plugin.
The plugin should work with D4 and D6 as well. If you have connected neato robot, please [tell me](https://github.com/naofireblade/homebridge-neato/issues) about your experience with this plugin.
## Contributors
Many thanks go to
- [ghulands](https://github.com/ghulands) for finding and fixing a bug when no robot is associated with the neato account
- [Berkay](https://github.com/btutal) for adding the schema file to use the plugin with homebridge-config-ui-x
- [Antoine de Maleprade](https://github.com/az0uz) for adding the zone cleaning feature

23
config.schema.json Normal file
View File

@@ -0,0 +1,23 @@
{
"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",
"type": "string",
"required": true,
"format": "email",
"description": "Your Email Address"
},
"password": {
"title": "password",
"type": "string",
"required": true,
"description": "Your Password"
}
}
}
}

445
index.js
View File

@@ -17,42 +17,57 @@ function NeatoVacuumRobotPlatform(log, config) {
this.serial = "1-3-3-7";
this.email = config['email'];
this.password = config['password'];
this.hiddenServices = ('disabled' in config ? config['disabled'] : '');
// default off
this.refresh = ('refresh' in config ? parseInt(config['refresh']) : 0);
// must be integer and positive
this.refresh = (typeof this.refresh !=='number' || (this.refresh%1)!==0 || this.refresh < 0) ? 0 : this.refresh;
// minimum 60s
this.refresh = (this.refresh > 0 && this.refresh < 60) ? 60 : this.refresh;
if ('refresh' in config && config['refresh'] !== 'auto') {
// parse config parameter
this.refresh = parseInt(config['refresh']);
// must be integer and positive
this.refresh = (typeof this.refresh !== 'number' || (this.refresh % 1) !== 0 || this.refresh < 0) ? 60 : this.refresh;
// minimum 60s to save some load on the neato servers
this.refresh = (this.refresh > 0 && this.refresh < 60) ? 60 : this.refresh;
}
// default auto
else {
this.refresh = 'auto';
}
debug("Refresh is set to: " + this.refresh);
}
NeatoVacuumRobotPlatform.prototype = {
accessories: function(callback) {
this.accessories = [];
accessories: function (callback) {
let accessories = [];
let that = this;
this.robots = this.getRobots(function () {
this.getRobots(function () {
for (var i = 0; i < that.robots.length; i++) {
that.log("Found robot #" + (i+1) + ": " + that.robots[i].name);
that.log("Found robot #" + (i + 1) + " named \"" + that.robots[i].name + "\" with serial \"" + that.robots[i]._serial + "\"");
var robotAccessory = new NeatoVacuumRobotAccessory(that.robots[i], that);
that.accessories.push(robotAccessory);
accessories.push(robotAccessory);
that.robots[i].maps.forEach((map) => {
map.boundaries.forEach((boundary) => {
if (boundary.type === "polygon") {
accessories.push(new NeatoVacuumRobotAccessory(that.robots[i], that, boundary))
}
})
})
}
callback(that.accessories);
callback(accessories);
});
},
getRobots: function(callback) {
debug("Get all robots");
getRobots: function (callback) {
debug("Loading your robots");
let client = new botvac.Client();
let that = this;
client.authorize(this.email, this.password, false, function (error) {
client.authorize(this.email, this.password, false, (error) => {
if (error) {
that.log(error);
that.log.error("Can't log on to neato cloud. Please check your credentials.");
callback();
}
else {
client.getRobots(function (error, robots) {
client.getRobots((error, robots) => {
if (error) {
that.log(error);
that.log.error("Successful login but can't connect to your neato robot.");
@@ -61,11 +76,40 @@ NeatoVacuumRobotPlatform.prototype = {
else {
if (robots.length === 0) {
that.log.error("Successful login but no robots associated with your account.");
callback();
that.robots = [];
callback();
}
else {
that.robots = robots;
callback();
debug("Found " + robots.length + " robots");
let updatedRobotCount = 0;
that.robots = robots;
that.robots.forEach((robot) => {
robot.getPersistentMaps((error, result) => {
if (error) {
that.log("Error updating persistent maps: " + error + ": " + result);
callback();
return;
}
robot.maps = result;
let processedMapCount = 0
robot.maps.forEach((map) => {
robot.getMapBoundaries(map.id, (error, result) => {
if(error) {
this.log("error getting boundaries: " + error + ": " + result)
} else {
map.boundaries = result.boundaries;
}
processedMapCount++;
if(processedMapCount == robot.maps.length) {
updatedRobotCount++
if (updatedRobotCount === that.robots.length) {
callback();
}
}
})
})
})
})
}
}
});
@@ -74,29 +118,49 @@ NeatoVacuumRobotPlatform.prototype = {
}
}
function NeatoVacuumRobotAccessory(robot, platform) {
function NeatoVacuumRobotAccessory(robot, platform, boundary) {
this.platform = platform;
this.boundary = boundary;
this.log = platform.log;
this.refresh = platform.refresh;
this.hiddenServices = platform.hiddenServices;
this.robot = robot;
this.name = robot.name;
if(!this.boundary) {
this.name = robot.name;
} else {
this.name = this.robot.name + ' - ' + this.boundary.name;
}
this.lastUpdate = null;
this.vacuumRobotCleanService = new Service.Switch(this.name + " Clean", "clean");
this.vacuumRobotGoToDockService = new Service.Switch(this.name + " Go to Dock", "goToDock");
this.vacuumRobotDockStateService = new Service.OccupancySensor(this.name + " Dock", "dockState");
this.vacuumRobotEcoService = new Service.Switch(this.name + " Eco Mode", "eco");
this.vacuumRobotScheduleService = new Service.Switch(this.name + " Schedule", "schedule");
this.vacuumRobotBatteryService = new Service.BatteryService("Battery", "battery");
this.updateRobotTimer();
if(!this.boundary) {
this.vacuumRobotCleanService = new Service.Switch("Clean", "clean");
this.vacuumRobotGoToDockService = new Service.Switch(this.name + " Go to Dock", "goToDock");
this.vacuumRobotDockStateService = new Service.OccupancySensor(this.name + " Dock", "dockState");
this.vacuumRobotEcoService = new Service.Switch(this.name + " Eco Mode", "eco");
this.vacuumRobotNoGoLinesService = new Service.Switch(this.name + " NoGo Lines", "noGoLines");
this.vacuumRobotExtraCareService = new Service.Switch(this.name + " Extra Care", "extraCare");
this.vacuumRobotScheduleService = new Service.Switch(this.name + " Schedule", "schedule");
} else {
const splitName = boundary.name.split(' ');
let serviceName = "Clean the " + boundary.name;
if(splitName.length >= 2 && splitName[splitName.length-2].match(/[']s$/g)){
serviceName = "Clean " + boundary.name;
}
this.vacuumRobotCleanBoundaryService =
new Service.Switch(serviceName, "cleanBoundary:" + boundary.id);
this.log("Adding zone cleaning for: " + boundary.name);
}
this.updateRobotTimer();
}
NeatoVacuumRobotAccessory.prototype = {
identify: function (callback) {
let that = this;
this.updateRobot(function() {
this.updateRobot(function () {
// hide serial and secret in log
let _serial = that.robot._serial;
let _secret = that.robot._secret;
@@ -105,19 +169,29 @@ NeatoVacuumRobotAccessory.prototype = {
that.log(that.robot);
that.robot._serial = _serial;
that.robot._secret = _secret;
callback();
});
},
getServices: function () {
debug(this.robot._serial);
this.informationService = new Service.AccessoryInformation();
this.informationService
.setCharacteristic(Characteristic.Name, this.robot.name)
this.informationService = new Service.AccessoryInformation();
this.informationService
.setCharacteristic(Characteristic.Manufacturer, "Neato Robotics")
.setCharacteristic(Characteristic.Model, "Coming soon")
.setCharacteristic(Characteristic.SerialNumber, this.robot._serial);
if(!this.boundary) {
this.informationService
.setCharacteristic(Characteristic.Name, this.robot.name)
} else {
this.informationService
.setCharacteristic(Characteristic.Name, this.robot.name + ' - ' + this.boundary.name)
}
this.vacuumRobotBatteryService.getCharacteristic(Characteristic.BatteryLevel).on('get', this.getBatteryLevel.bind(this));
this.vacuumRobotBatteryService.getCharacteristic(Characteristic.ChargingState).on('get', this.getBatteryChargingState.bind(this));
this.services = [this.informationService, this.vacuumRobotBatteryService];
if(!this.boundary) {
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('set', this.setClean.bind(this));
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('get', this.getClean.bind(this));
@@ -129,51 +203,132 @@ NeatoVacuumRobotAccessory.prototype = {
this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('set', this.setEco.bind(this));
this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('get', this.getEco.bind(this));
this.vacuumRobotNoGoLinesService.getCharacteristic(Characteristic.On).on('set', this.setNoGoLines.bind(this));
this.vacuumRobotNoGoLinesService.getCharacteristic(Characteristic.On).on('get', this.getNoGoLines.bind(this));
this.vacuumRobotExtraCareService.getCharacteristic(Characteristic.On).on('set', this.setExtraCare.bind(this));
this.vacuumRobotExtraCareService.getCharacteristic(Characteristic.On).on('get', this.getExtraCare.bind(this));
this.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).on('set', this.setSchedule.bind(this));
this.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).on('get', this.getSchedule.bind(this));
this.vacuumRobotBatteryService.getCharacteristic(Characteristic.BatteryLevel).on('get', this.getBatteryLevel.bind(this));
this.vacuumRobotBatteryService.getCharacteristic(Characteristic.ChargingState).on('get', this.getBatteryChargingState.bind(this));
this.services.push(this.vacuumRobotCleanService);
return [this.informationService, this.vacuumRobotCleanService, this.vacuumRobotGoToDockService, this.vacuumRobotDockStateService, this.vacuumRobotEcoService,
this.vacuumRobotScheduleService, this.vacuumRobotBatteryService];
if (this.hiddenServices.indexOf('dock') === -1)
this.services.push(this.vacuumRobotGoToDockService);
if (this.hiddenServices.indexOf('dockstate') === -1)
this.services.push(this.vacuumRobotDockStateService);
if (this.hiddenServices.indexOf('eco') === -1)
this.services.push(this.vacuumRobotEcoService);
if (this.hiddenServices.indexOf('nogolines') === -1)
this.services.push(this.vacuumRobotNoGoLinesService);
if (this.hiddenServices.indexOf('extracare') === -1)
this.services.push(this.vacuumRobotExtraCareService);
if (this.hiddenServices.indexOf('schedule') === -1)
this.services.push(this.vacuumRobotScheduleService);
}
if(this.boundary){
this.vacuumRobotCleanBoundaryService.getCharacteristic(Characteristic.On).on('set', (on, serviceCallback) => {
this.setCleanBoundary(this.boundary.id, on, serviceCallback)
})
this.vacuumRobotCleanBoundaryService.getCharacteristic(Characteristic.On).on('get', (serviceCallback) => {
this.getCleanBoundary(this.boundary.id, serviceCallback);
})
this.services.push(this.vacuumRobotCleanBoundaryService);
}
return this.services;
},
setCleanBoundary: function (boundaryId, on, callback) {
this.updateRobot((error, result) => {
if(on){
if(this.robot.canStart) {
this.log("Starting to clean: "+boundaryId);
this.robot.startCleaningBoundary(this.eco, this.extraCare, boundaryId, (error, result) => {
if (error){
this.log(error+": "+JSON.stringify(result));
}
callback();
})
return
} else {
this.log("Error, robot is already cleaning");
}
} else {
if (this.robot.canPause) {
debug(this.name + ": Pause cleaning");
this.robot.pauseCleaning(callback);
return;
}
else {
debug(this.name + ": Already stopped");
}
}
callback();
});
},
getCleanBoundary: function (boundaryId, callback) {
this.updateRobot((error, result) => {
callback(false, this.robot.canPause && (this.robot.cleaningBoundaryId == boundaryId));
});
},
setClean: function (on, callback) {
let that = this;
this.updateRobot(function (error, result) {
if (on) {
if (that.robot.canResume || that.robot.canStart) {
// wait for robot to start and then start a short timer to recognize when he can go to dock or is finished
setTimeout(function() {
clearTimeout(that.timer);
that.updateRobotTimer();
}, 10000);
if (on) {
if (that.robot.canResume || that.robot.canStart) {
if (that.robot.canResume) {
debug(that.name + ": Resume cleaning");
that.robot.resumeCleaning(callback);
// start extra update robot timer if refresh is set to "auto"
if (that.refresh === 'auto') {
setTimeout(function () {
clearTimeout(that.timer);
that.updateRobotTimer();
}, 60 * 1000);
}
if (that.robot.canResume) {
debug(that.name + ": Resume cleaning");
that.robot.resumeCleaning(callback);
}
else {
let eco = that.vacuumRobotEcoService.getCharacteristic(Characteristic.On).value;
let extraCare = that.vacuumRobotExtraCareService.getCharacteristic(Characteristic.On).value;
let nogoLines = that.vacuumRobotNoGoLinesService.getCharacteristic(Characteristic.On).value;
debug(that.name + ": Start cleaning (eco: " + eco + ", extraCare: " + extraCare + ", nogoLines: " + nogoLines + ")");
that.robot.startCleaning(
eco,
extraCare ? 2 : 1,
nogoLines,
function (error, result) {
if (error) {
that.log.error(error + ": " + result);
callback(true);
}
else {
debug(that.name + ": Start cleaning");
that.robot.startCleaning(that.robot.eco, 2, callback);
callback();
}
}
else {
debug(that.name + ": Cant start, maybe already cleaning");
callback();
}
});
}
}
else {
if (that.robot.canPause) {
debug(that.name + ": Pause cleaning");
that.robot.pauseCleaning(callback);
}
else {
debug(that.name + ": Already stopped");
callback();
}
debug(that.name + ": Cant start, maybe already cleaning");
callback();
}
}
else {
if (that.robot.canPause) {
debug(that.name + ": Pause cleaning");
that.robot.pauseCleaning(callback);
}
else {
debug(that.name + ": Already stopped");
callback();
}
}
});
},
@@ -184,19 +339,18 @@ NeatoVacuumRobotAccessory.prototype = {
if (that.robot.canPause) {
debug(that.name + ": Pause cleaning to go to dock");
that.robot.pauseCleaning(function (error, result) {
setTimeout(function() {
setTimeout(function () {
debug("Go to dock");
that.robot.sendToBase(callback);
that.robot.sendToBase(callback);
}, 1000);
});
}
else if (that.robot.canGoToBase)
{
else if (that.robot.canGoToBase) {
debug(that.name + ": Go to dock");
that.robot.sendToBase(callback);
}
else {
debug(that.name + ": Can't go to dock at the moment");
that.log.warn(that.name + ": Can't go to dock at the moment");
callback();
}
} else {
@@ -211,21 +365,33 @@ NeatoVacuumRobotAccessory.prototype = {
callback();
},
setNoGoLines: function (on, callback) {
debug(this.name + ": " + (on ? "Enable nogo lines" : "Disable nogo lines"));
this.robot.noGoLines = on;
callback();
},
setExtraCare: function (on, callback) {
debug(this.name + ": " + (on ? "Enable extra care navigation" : "Disable extra care navigation"));
this.robot.navigationMode = on ? 2 : 1;
callback();
},
setSchedule: function (on, callback) {
let that = this;
this.updateRobot(function (error, result) {
if (on) {
debug(that.name + ": Enable schedule");
that.robot.enableSchedule(callback);
that.robot.enableSchedule(callback);
}
else {
debug(that.name + ": Disable schedule");
that.robot.disableSchedule(callback);
that.robot.disableSchedule(callback);
}
});
},
getClean: function(callback) {
getClean: function (callback) {
let that = this;
this.updateRobot(function (error, result) {
debug(that.name + ": Is cleaning: " + that.robot.canPause);
@@ -233,103 +399,132 @@ NeatoVacuumRobotAccessory.prototype = {
});
},
getGoToDock: function(callback) {
let that = this;
this.updateRobot(function (error, result) {
debug(that.name + ": Can go to dock: " + that.robot.dockHasBeenSeen);
callback(false, !that.robot.dockHasBeenSeen);
});
getGoToDock: function (callback) {
callback(false, false);
},
getDock: function(callback) {
getDock: function (callback) {
let that = this;
this.updateRobot(function (error, result) {
this.updateRobot(function () {
debug(that.name + ": Is docked: " + that.robot.isDocked);
callback(false, that.robot.isDocked);
callback(false, that.robot.isDocked ? 1 : 0);
});
},
getEco: function(callback) {
// dont load eco here, because we cant save the eco state on the robot
callback(false, this.robot.eco);
getEco: function (callback) {
let that = this;
this.updateRobot(function () {
debug(that.name + ": Is eco: " + that.robot.eco);
callback(false, that.robot.eco);
});
},
getSchedule: function(callback) {
getNoGoLines: function (callback) {
let that = this;
this.updateRobot(function (error, result) {
debug(that.name + ": Schedule: " + that.robot.isScheduleEnabled);
this.updateRobot(function () {
debug(that.name + ": Is nogo lines: " + that.robot.noGoLines);
callback(false, that.robot.noGoLines ? 1 : 0);
});
},
getExtraCare: function (callback) {
let that = this;
this.updateRobot(function () {
debug(that.name + ": Is extra care navigation: " + (that.robot.navigationMode == 2 ? true : false));
callback(false, that.robot.navigationMode == 2 ? 1 : 0);
});
},
getSchedule: function (callback) {
let that = this;
this.updateRobot(function () {
debug(that.name + ": Is schedule: " + that.robot.isScheduleEnabled);
callback(false, that.robot.isScheduleEnabled);
});
},
getBatteryLevel: function(callback) {
getBatteryLevel: function (callback) {
let that = this;
this.updateRobot(function (error, result) {
debug(that.name + ": Battery: " + that.robot.charge);
this.updateRobot(function () {
debug(that.name + ": Battery: " + that.robot.charge + "%");
callback(false, that.robot.charge);
});
},
getBatteryChargingState: function(callback) {
getBatteryChargingState: function (callback) {
let that = this;
this.updateRobot(function (error, result) {
this.updateRobot(function () {
debug(that.name + ": Is charging: " + that.robot.isCharging);
callback(false, that.robot.isCharging);
});
},
updateRobot: function(callback) {
updateRobot: function (callback) {
let that = this;
if (this.lastUpdate !== null && new Date() - this.lastUpdate < 2000) {
debug(this.name + ": Update (cached)");
callback();
}
else {
debug(this.name + ": Update (online)");
debug(this.name + ": Updating robot state");
this.robot.getState(function (error, result) {
if (error) {
that.log.error(error + ": " + result);
}
that.lastUpdate = new Date();
callback();
});
}
},
updateRobotTimer: function() {
let that = this;
debug(this.name + ": Timer called");
this.updateRobot(function (error, result) {
updateRobotTimer: function () {
let that = this;
this.updateRobot((error, result) => {
// only update these values if the state is different from the current one, otherwise we might accidentally start an action
if (that.vacuumRobotCleanService.getCharacteristic(Characteristic.On).value !== that.robot.canPause) {
that.vacuumRobotCleanService.setCharacteristic(Characteristic.On, that.robot.canPause);
}
if (!this.boundary) {
// only update these values if the state is different from the current one, otherwise we might accidentally start an action
if (that.vacuumRobotCleanService.getCharacteristic(Characteristic.On).value !== that.robot.canPause) {
that.vacuumRobotCleanService.setCharacteristic(Characteristic.On, that.robot.canPause);
}
if (that.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).value !== !that.robot.dockHasBeenSeen) {
that.vacuumRobotGoToDockService.setCharacteristic(Characteristic.On, !that.robot.dockHasBeenSeen);
}
// dock switch is on (dock not seen before) and dock has just been seen -> turn switch off
if (that.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).value == true && that.robot.dockHasBeenSeen) {
that.vacuumRobotGoToDockService.setCharacteristic(Characteristic.On, false);
}
if (that.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).value !== that.robot.isScheduleEnabled) {
that.vacuumRobotScheduleService.setCharacteristic(Characteristic.On, that.robot.isScheduleEnabled);
}
if (that.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).value !== that.robot.isScheduleEnabled) {
that.vacuumRobotScheduleService.setCharacteristic(Characteristic.On, that.robot.isScheduleEnabled);
}
// no commands here, values can be updated without problems
that.vacuumRobotDockStateService.setCharacteristic(Characteristic.OccupancyDetected, that.robot.isDocked);
that.vacuumRobotBatteryService.setCharacteristic(Characteristic.BatteryLevel, that.robot.charge);
that.vacuumRobotBatteryService.setCharacteristic(Characteristic.ChargingState, that.robot.isCharging);
// no commands here, values can be updated without problems
that.vacuumRobotDockStateService.setCharacteristic(Characteristic.OccupancyDetected, that.robot.isDocked ? 1 : 0);
that.vacuumRobotEcoService.setCharacteristic(Characteristic.On, that.robot.eco);
that.vacuumRobotNoGoLinesService.setCharacteristic(Characteristic.On, that.robot.noGoLines);
that.vacuumRobotExtraCareService.setCharacteristic(Characteristic.On, that.robot.navigationMode == 2 ? true : false);
// dont update eco, because we cant write that value onto the robot and dont want it to be overwritten in our plugin
} else {
if(this.vacuumRobotCleanBoundaryService.getCharacteristic(Characteristic.On).value !== that.robot.canPause) {
this.vacuumRobotCleanBoundaryService.setCharacteristic(Characteristic.On, that.robot.canPause);
}
}
if (that.robot.canPause) {
debug(that.name + ": Timer set (cleaning): 30s");
that.timer = setTimeout(that.updateRobotTimer.bind(that), 30 * 1000);
}
else if (that.refresh != 0) {
debug(that.name + ": Timer set (user): " + that.refresh + "s");
that.timer = setTimeout(that.updateRobotTimer.bind(that), that.refresh * 1000);
}
else {
debug(that.name + ": Timer stopped");
}
});
that.vacuumRobotBatteryService.setCharacteristic(Characteristic.BatteryLevel, that.robot.charge);
that.vacuumRobotBatteryService.setCharacteristic(Characteristic.ChargingState, that.robot.isCharging);
// robot is currently cleaning, update if refresh is set to auto or a specific interval
if (that.robot.canPause && that.refresh !== 0) {
let refreshTime = that.refresh === 'auto' ? 60 : that.refresh
debug("Updating state in background every " + refreshTime + " seconds while cleaning");
that.timer = setTimeout(that.updateRobotTimer.bind(that), refreshTime * 1000);
}
// robot is not cleaning, but a specific refresh interval is set
else if (that.refresh !== 'auto' && that.refresh !== 0) {
debug("Updating state in background every " + that.refresh + " seconds (user setting)");
that.timer = setTimeout(that.updateRobotTimer.bind(that), that.refresh * 1000);
}
else {
debug("Updating state in background disabled");
}
});
},
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "homebridge-neato",
"version": "0.4.0",
"version": "0.6.0",
"description": "A Neato vacuum robot plugin for homebridge.",
"license": "MIT",
"keywords": [
@@ -13,14 +13,30 @@
"homebridge": ">=0.2.0"
},
"author": {
"name": "Arne Blumentritt"
"name": "Arne Blumentritt",
"url2": "https://github.com/naofireblade"
},
"contributors": [
{
"name": "ghulands",
"url": "https://github.com/ghulands"
},
{
"name": "Berkay",
"url": "https://github.com/btutal"
},
{
"name": "Antoine de Maleprade",
"url": "https://github.com/az0uz"
}
],
"repository": {
"type": "git",
"url": "git://github.com/naofireblade/homebridge-neato.git"
},
"dependencies": {
"node-botvac": ">=0.1.5",
"debug": "^2.2.0"
"debug": "^2.2.0",
"node-botvac": ">=0.3.0",
"uuid": "^3.3.2"
}
}