Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0f8fb1dedf | ||
|
e01fb8df28 | ||
|
8cb6ecf8a5 | ||
|
36e8496108 | ||
|
b2ddecc827 | ||
|
5dbdb18c58 | ||
|
d49cab1e97 | ||
|
92eabfe5cd | ||
|
67b930653f | ||
|
579bd32a93 | ||
|
a606d4c632 | ||
|
3a4327f7e9 | ||
|
cbfbb26b14 |
17
.gitattributes
vendored
17
.gitattributes
vendored
@@ -1,17 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
47
.gitignore
vendored
47
.gitignore
vendored
@@ -1,47 +0,0 @@
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# =========================
|
||||
# Operating System Files
|
||||
# =========================
|
||||
|
||||
# OSX
|
||||
# =========================
|
||||
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
17
CHANGELOG.md
17
CHANGELOG.md
@@ -5,3 +5,20 @@
|
||||
* Added enable and disable schedule
|
||||
* Added enable and disable eco mode
|
||||
* Added battery info
|
||||
|
||||
## 0.2.0
|
||||
|
||||
* Added dock info
|
||||
* Improved logging to use a debug library
|
||||
|
||||
## 0.2.1
|
||||
|
||||
* Improved the go to dock command
|
||||
|
||||
## 0.3.0
|
||||
|
||||
* Added periodic refresh of robot state while cleaning
|
||||
* Added optional periodic refresh of robot state while not cleaning
|
||||
* Improved go to dock switch to be enabled as soon as possible without manual refresh
|
||||
* Improved switches to indicate the time an action needs to complete
|
||||
* Improved eco mode to not be overwritten by robot state update
|
48
README.md
48
README.md
@@ -1,40 +1,50 @@
|
||||
# homebridge-neato
|
||||
|
||||
This is a plugin to control your [Neato](https://www.neatorobotics.com/) vacuum robot.
|
||||
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).
|
||||
|
||||
# Features
|
||||
|
||||
- Start and pause cleaning
|
||||
- Return to dock\*
|
||||
- Enable and disable schedule
|
||||
- Enable and disable eco mode
|
||||
- Get battery info
|
||||
- Get dock info
|
||||
- Periodic refresh of robot state
|
||||
|
||||
\* The robot needs to clean for some seconds before he knows where his dock is. After this time the switch to send him home will be automatically available.
|
||||
|
||||
**Hint:** To control the robot with your own commands just set up a scene with the name of your choice.
|
||||
|
||||
# Installation
|
||||
|
||||
1. Install homebridge using: npm install -g homebridge
|
||||
2. Install this plugin using: npm install -g homebridge-neato
|
||||
3. Update your configuration file. See the sample below.
|
||||
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 sample:
|
||||
### Configuration
|
||||
|
||||
Add the following information to your config file. Change the values for name, email and password.
|
||||
|
||||
The parameter **refresh** is optional (default off) and adjusts in what interval changes in 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).
|
||||
|
||||
```json
|
||||
"accessories": [
|
||||
{
|
||||
"accessory": "NeatoVacuumRobot",
|
||||
"name": "YourRobot",
|
||||
"email": "YourEmail",
|
||||
"password": "YourPassword"
|
||||
"password": "YourPassword",
|
||||
"refresh": "120"
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
# Features
|
||||
|
||||
- Atart and pause cleaning
|
||||
- Return to base
|
||||
- Enable and disable schedule
|
||||
- Enable and disable eco mode
|
||||
- Get battery info
|
||||
|
||||
# Tested robots
|
||||
|
||||
- BotVac Connected Firmware 2.2.0
|
||||
- BotVac Connected (Firmware 2.2.0)
|
||||
|
||||
if you have another connected neato robot, please [tell me](https://github.com/naofireblade/homebridge-neato/issues/new) your experience with this plugin.
|
||||
If you have another connected neato robot, please [tell me](https://github.com/naofireblade/homebridge-neato/issues) about your experience with this plugin.
|
1
_config.yml
Normal file
1
_config.yml
Normal file
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-cayman
|
235
index.js
235
index.js
@@ -1,8 +1,18 @@
|
||||
"use strict";
|
||||
var inherits = require('util').inherits;
|
||||
var botvac = require('node-botvac');
|
||||
var inherits = require('util').inherits,
|
||||
debug = require('debug')('homebridge-neato'),
|
||||
botvac = require('node-botvac'),
|
||||
|
||||
var Service, Characteristic;
|
||||
Service,
|
||||
Characteristic,
|
||||
vacuumRobotCleanService,
|
||||
vacuumRobotGoToDockService,
|
||||
vacuumRobotDockStateService,
|
||||
vacuumRobotEcoService,
|
||||
vacuumRobotScheduleService,
|
||||
vacuumRobotBatteryService,
|
||||
refresh,
|
||||
timer
|
||||
|
||||
module.exports = function (homebridge) {
|
||||
Service = homebridge.hap.Service;
|
||||
@@ -17,8 +27,23 @@ function NeatoVacuumRobot(log, config) {
|
||||
this.email = config['email'];
|
||||
this.password = config['password'];
|
||||
|
||||
// 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 = (0 < this.refresh < 60) ? 60 : this.refresh;
|
||||
|
||||
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.lastUpdate = null;
|
||||
this.robot = null;
|
||||
this.getStateTimer();
|
||||
}
|
||||
|
||||
NeatoVacuumRobot.prototype = {
|
||||
@@ -34,121 +59,147 @@ NeatoVacuumRobot.prototype = {
|
||||
.setCharacteristic(Characteristic.Model, this.name)
|
||||
.setCharacteristic(Characteristic.SerialNumber, this.serial);
|
||||
|
||||
this.vacuumRobotCleanService = new Service.Switch(this.name + " Clean", "clean");
|
||||
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('set', this.clean.bind(this));
|
||||
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('set', this.setClean.bind(this));
|
||||
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('get', this.getClean.bind(this));
|
||||
|
||||
this.vacuumRobotDockService = new Service.Switch(this.name + " Dock", "dock");
|
||||
this.vacuumRobotDockService.getCharacteristic(Characteristic.On).on('set', this.dock.bind(this));
|
||||
this.vacuumRobotDockService.getCharacteristic(Characteristic.On).on('get', this.getDock.bind(this));
|
||||
this.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).on('set', this.setGoToDock.bind(this));
|
||||
this.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).on('get', this.getGoToDock.bind(this));
|
||||
|
||||
this.vacuumRobotEcoService = new Service.Switch(this.name + " Eco Mode", "eco");
|
||||
this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('set', this.eco.bind(this));
|
||||
this.vacuumRobotDockStateService.getCharacteristic(Characteristic.OccupancyDetected).on('get', this.getDock.bind(this));
|
||||
|
||||
this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('set', this.setEco.bind(this));
|
||||
this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('get', this.getEco.bind(this));
|
||||
|
||||
this.vacuumRobotScheduleService = new Service.Switch(this.name + " Schedule", "schedule");
|
||||
this.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).on('set', this.schedule.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 = new Service.BatteryService("Battery", "battery");
|
||||
this.vacuumRobotBatteryService.getCharacteristic(Characteristic.BatteryLevel).on('get', this.getBatteryLevel.bind(this));
|
||||
this.vacuumRobotBatteryService.getCharacteristic(Characteristic.ChargingState).on('get', this.getBatteryChargingState.bind(this));
|
||||
|
||||
return [this.informationService, this.vacuumRobotCleanService, this.vacuumRobotDockService, this.vacuumRobotEcoService,
|
||||
return [this.informationService, this.vacuumRobotCleanService, this.vacuumRobotGoToDockService, this.vacuumRobotDockStateService, this.vacuumRobotEcoService,
|
||||
this.vacuumRobotScheduleService, this.vacuumRobotBatteryService];
|
||||
},
|
||||
|
||||
clean: function (on, callback) {
|
||||
setClean: function (on, callback) {
|
||||
let that = this;
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
if (on) {
|
||||
this.getState(function (error, result) {
|
||||
that.log(that.robot);
|
||||
if (that.robot.canResume === true) {
|
||||
that.log("Resume cleaning");
|
||||
that.robot.resumeCleaning(function (error, result) {
|
||||
that.log(result);
|
||||
});
|
||||
if (that.robot.canResume || that.robot.canStart) {
|
||||
// wait for robot to start and then disable the old timer and enable it again (with a shorter interval)
|
||||
setTimeout(function() {
|
||||
clearTimeout(that.timer);
|
||||
that.getStateTimer();
|
||||
}, 10000);
|
||||
|
||||
if (that.robot.canResume) {
|
||||
debug("Resume cleaning");
|
||||
that.robot.resumeCleaning(callback);
|
||||
}
|
||||
else {
|
||||
that.log("Start cleaning");
|
||||
that.robot.startCleaning(that.robot.eco, function (error, result) {
|
||||
that.log(result);
|
||||
});
|
||||
debug("Start cleaning");
|
||||
that.robot.startCleaning(that.robot.eco, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.log("Pause cleaning");
|
||||
this.robot.pauseCleaning(false, function (error, result) {
|
||||
that.log(result);
|
||||
});
|
||||
}
|
||||
debug("Already cleaning");
|
||||
callback();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (that.robot.canPause) {
|
||||
debug("Pause cleaning");
|
||||
that.robot.pauseCleaning(callback);
|
||||
}
|
||||
else {
|
||||
debug("Already stopped");
|
||||
callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
dock: function (on, callback) {
|
||||
setGoToDock: function (on, callback) {
|
||||
let that = this;
|
||||
that.log(that.robot);
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
if (on) {
|
||||
that.log("Send to dock");
|
||||
that.robot.sendToBase(false, function (error, result) {
|
||||
that.log(result);
|
||||
if (that.robot.canPause) {
|
||||
debug("Pause cleaning to go to dock");
|
||||
that.robot.pauseCleaning(function (error, result) {
|
||||
setTimeout(function() {
|
||||
debug("Go to dock");
|
||||
that.robot.sendToBase(callback);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
else if (that.robot.canGoToBase)
|
||||
{
|
||||
debug("Go to dock");
|
||||
that.robot.sendToBase(callback);
|
||||
}
|
||||
else {
|
||||
debug("Can't go to dock at the moment");
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
eco: function (on, callback) {
|
||||
this.log(on ? "Enable eco mode" : "Disable eco mode");
|
||||
setEco: function (on, callback) {
|
||||
debug(on ? "Enable eco mode" : "Disable eco mode");
|
||||
this.robot.eco = on;
|
||||
callback();
|
||||
},
|
||||
|
||||
schedule: function (on, callback) {
|
||||
setSchedule: function (on, callback) {
|
||||
let that = this;
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
if (on) {
|
||||
this.log("Enable schedule");
|
||||
this.robot.enableSchedule(false, function (error, result) {
|
||||
onsole.log(result);
|
||||
});
|
||||
debug("Enable schedule");
|
||||
that.robot.enableSchedule(callback);
|
||||
}
|
||||
else {
|
||||
this.log("Disable schedule");
|
||||
this.robot.disableSchedule(false, function (error, result) {
|
||||
onsole.log(result);
|
||||
});
|
||||
debug("Disable schedule");
|
||||
that.robot.disableSchedule(callback);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
getClean: function(callback) {
|
||||
let that = this;
|
||||
this.getState(function (error, result) {
|
||||
that.log("Is cleaning: " + that.robot.canPause);
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
debug("Is cleaning: " + that.robot.canPause);
|
||||
callback(false, that.robot.canPause);
|
||||
});
|
||||
},
|
||||
|
||||
getGoToDock: function(callback) {
|
||||
let that = this;
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
debug("Can go to dock: " + that.robot.dockHasBeenSeen);
|
||||
callback(false, !that.robot.dockHasBeenSeen);
|
||||
});
|
||||
},
|
||||
|
||||
getDock: function(callback) {
|
||||
let that = this;
|
||||
this.getState(function (error, result) {
|
||||
that.log("Can go to dock: " + that.robot.canGoToBase);
|
||||
that.log("Is docked: " + that.robot.isDocked);
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
debug("Is docked: " + that.robot.isDocked);
|
||||
debug(that.robot);
|
||||
callback(false, that.robot.isDocked);
|
||||
});
|
||||
},
|
||||
|
||||
getEco: function(callback) {
|
||||
let that = this;
|
||||
this.getState(function (error, result) {
|
||||
that.log("Eco mode: " + that.robot.eco);
|
||||
callback(false, that.robot.eco);
|
||||
});
|
||||
// dont load eco here, because we cant save the eco state on the robot
|
||||
callback(false, this.robot.eco);
|
||||
},
|
||||
|
||||
getSchedule: function(callback) {
|
||||
let that = this;
|
||||
this.getState(function (error, result) {
|
||||
that.log("Schedule: " + that.robot.isScheduleEnabled);
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
debug("Schedule: " + that.robot.isScheduleEnabled);
|
||||
callback(false, that.robot.isScheduleEnabled);
|
||||
});
|
||||
},
|
||||
@@ -156,40 +207,40 @@ NeatoVacuumRobot.prototype = {
|
||||
|
||||
getBatteryLevel: function(callback) {
|
||||
let that = this;
|
||||
this.getState(function (error, result) {
|
||||
that.log("Battery: " + that.robot.charge);
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
debug("Battery: " + that.robot.charge);
|
||||
callback(false, that.robot.charge);
|
||||
});
|
||||
},
|
||||
|
||||
getBatteryChargingState: function(callback) {
|
||||
let that = this;
|
||||
this.getState(function (error, result) {
|
||||
that.log("Is charging: " + that.robot.isCharging);
|
||||
this.getStateAndRobot(function (error, result) {
|
||||
debug("Is charging: " + that.robot.isCharging);
|
||||
callback(false, that.robot.isCharging);
|
||||
});
|
||||
},
|
||||
|
||||
getState: function(callback) {
|
||||
getStateAndRobot: function(callback) {
|
||||
let that = this;
|
||||
if (this.robot === null)
|
||||
{
|
||||
this.getRobot(function (error, result) {
|
||||
that._getState(callback);
|
||||
that.getState(callback);
|
||||
});
|
||||
}
|
||||
else {
|
||||
that._getState(callback);
|
||||
that.getState(callback);
|
||||
}
|
||||
},
|
||||
|
||||
_getState: function(callback) {
|
||||
getState: function(callback) {
|
||||
if (this.lastUpdate !== null && new Date() - this.lastUpdate < 2000) {
|
||||
//this.log("Get state (cached)");
|
||||
debug("Get state (cached)");
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
//this.log("Get state (new)");
|
||||
debug("Get state (new)");
|
||||
let that = this;
|
||||
this.robot.getState(function (error, result) {
|
||||
that.lastUpdate = new Date();
|
||||
@@ -198,8 +249,47 @@ NeatoVacuumRobot.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
getStateTimer: function() {
|
||||
debug("Timer called");
|
||||
let that = this;
|
||||
this.getStateAndRobot(function (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 (that.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).value !== !that.robot.dockHasBeenSeen) {
|
||||
that.vacuumRobotGoToDockService.setCharacteristic(Characteristic.On, !that.robot.dockHasBeenSeen);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// dont update eco, because we cant write that value onto the robot and dont want it to be overwritten in our plugin
|
||||
|
||||
if (that.robot.canPause) {
|
||||
debug("Short timer set: 30s");
|
||||
that.timer = setTimeout(that.getStateTimer.bind(that), 30 * 1000);
|
||||
}
|
||||
else if (that.refresh != 0) {
|
||||
debug("Long timer set: " + that.refresh + "s");
|
||||
that.timer = setTimeout(that.getStateTimer.bind(that), that.refresh * 1000);
|
||||
}
|
||||
else {
|
||||
debug("Disabled timer");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getRobot: function(callback) {
|
||||
//this.log("Get robot");
|
||||
debug("Get robot");
|
||||
let client = new botvac.Client();
|
||||
let that = this;
|
||||
client.authorize(this.email, this.password, false, function (error) {
|
||||
@@ -214,6 +304,7 @@ NeatoVacuumRobot.prototype = {
|
||||
else {
|
||||
that.robot = robots[0];
|
||||
that.log("Found robot: " + that.robot.name);
|
||||
debug(that.robot);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
11
package.json
11
package.json
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"name": "homebridge-neato",
|
||||
"version": "0.1.0",
|
||||
"description": "control your neato vacuum robot",
|
||||
"version": "0.3.0",
|
||||
"description": "A Neato vacuum robot plugin for homebridge.",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"homebridge-plugin"
|
||||
"homebridge-plugin",
|
||||
"neato",
|
||||
"botvac"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=0.12.0",
|
||||
@@ -18,6 +20,7 @@
|
||||
"url": "git://github.com/naofireblade/homebridge-neato.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-botvac": ">=0.1.4"
|
||||
"node-botvac": "^0.1.4",
|
||||
"debug": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user