Compare commits
81 Commits
v0.4.4
...
feature-la
Author | SHA1 | Date | |
---|---|---|---|
|
0767779172 | ||
|
bdb5807aeb | ||
|
010e177306 | ||
|
3af668399b | ||
|
877c3d7d26 | ||
|
77945f8420 | ||
|
5ff3951668 | ||
|
b83d30cfad | ||
|
b53ef4ff2f | ||
|
d8ca308338 | ||
|
75180b27cb | ||
|
b8971b64a9 | ||
|
32e47d0a8f | ||
|
f0dd89353e | ||
|
d809be5b03 | ||
|
6e5b0d522c | ||
|
9af5fe8a26 | ||
|
61b66444ac | ||
|
7197d78f33 | ||
|
fa25b0d6a5 | ||
|
b7c2f82173 | ||
|
09e19d38cf | ||
|
500ae64e0f | ||
|
12dd6d4676 | ||
|
5402123340 | ||
|
e75686e665 | ||
|
bef37d88c8 | ||
|
af54046927 | ||
|
1a4308ac40 | ||
|
46ba5e5f30 | ||
|
b8fa1db8ae | ||
|
0e92f09079 | ||
|
73bc399d64 | ||
|
e49b4af85a | ||
|
139f415a42 | ||
|
c789598019 | ||
|
c6def8c0fc | ||
|
114ff70d60 | ||
|
7594843bb3 | ||
|
0ac882414a | ||
|
6a57eaa57e | ||
|
8822670f9b | ||
|
150b8973ee | ||
|
ca2af3968c | ||
|
6f19a189b2 | ||
|
5139929bce | ||
|
a3b64b7c53 | ||
|
0338580c0a | ||
|
54f303394e | ||
|
c43a666378 | ||
|
20c54a02e8 | ||
|
1436e4b342 | ||
|
db8305bbee | ||
|
f795781d2a | ||
|
3cfde323a8 | ||
|
4a97487400 | ||
|
5ea9dde49c | ||
|
8ef24c9d40 | ||
|
979dc40ccf | ||
|
7d824ee0b9 | ||
|
b87e49e12f | ||
|
afe7d690ef | ||
|
442b91c347 | ||
|
55020c005b | ||
|
7c72aabb25 | ||
|
769712405a | ||
|
7b70d8f076 | ||
|
e1754e02ed | ||
|
0b864eb229 | ||
|
1d1fa121a4 | ||
|
6c6bb1c204 | ||
|
577e62ea32 | ||
|
fbec31602f | ||
|
42fa0399f8 | ||
|
0de549dd41 | ||
|
7fef07df0a | ||
|
9e9dd80547 | ||
|
b7ec93953e | ||
|
ad41c1679d | ||
|
89f6f233a5 | ||
|
88f217e2b1 |
75
.gitignore
vendored
Normal file
75
.gitignore
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/dist-server
|
||||
/dist-e2e
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
*.iml
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/libpeerconnection.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
package-lock.json
|
72
CHANGELOG.md
72
CHANGELOG.md
@@ -49,4 +49,74 @@
|
||||
|
||||
## 0.4.4
|
||||
|
||||
* Fixed config parameter to disable switches/sensors not optional
|
||||
* 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
|
||||
|
||||
## 0.6.0
|
||||
|
||||
* Added support for zone cleaning
|
||||
|
||||
## 0.6.1
|
||||
|
||||
* Fixed homebridge startup failed when robot does not support zone cleaning
|
||||
|
||||
## 0.6.2
|
||||
|
||||
* Fixed homebridge startup failed when robot does not support mapping
|
||||
|
||||
## 0.6.3
|
||||
|
||||
* Fixed homebridge crash when robot has a map without zones
|
||||
* Fixed homebridge crash when homebridge has no internet connection or the neato servers are offline
|
||||
* Fixed homebridge crash when 2 zones have the same name
|
||||
|
||||
## 0.7.0
|
||||
|
||||
* Added find me function
|
||||
* Added spot cleaning function with individual spot size and repeat option
|
||||
* Added model and firmware information to homekit
|
||||
* Added logic to be able to change the currently cleaned room
|
||||
* Improved number of requests when having multiple rooms
|
||||
* Fixed room switches not taking eco and extraCare mode into account
|
||||
* Fixed room switches not supporting pause/resume
|
||||
|
||||
## 0.7.1
|
||||
* Fixed robot not shown before setting up a floor plan
|
||||
|
||||
## 0.7.2
|
||||
* Fixed homebridge crash with multiple robots per account
|
||||
|
||||
## 0.7.3
|
||||
* Fixed warnings since homebridge 1.3.0
|
78
README.md
78
README.md
@@ -1,30 +1,51 @@
|
||||
# homebridge-neato
|
||||
[](https://www.npmjs.com/package/homebridge-neato)
|
||||
[](https://www.npmjs.com/package/homebridge-neato?activeTab=versions)
|
||||
[](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 like this plugin and find it useful, I would be forever grateful for your support:
|
||||
|
||||
If you update from a previous version 0.3.x you have to adapt your config.
|
||||
<a href="https://www.buymeacoffee.com/naofireblade" target="_blank"><img width="140" src="https://bmc-cdn.nyc3.digitaloceanspaces.com/BMC-button-images/custom_images/orange_img.png" alt="Buy Me A Coffee"></a>
|
||||
|
||||
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
|
||||
- Support for multiple robots
|
||||
- Extra care navigation
|
||||
- House Cleaning
|
||||
- Eco mode
|
||||
- Extra care navigation
|
||||
- Nogo lines
|
||||
- Zone cleaning <sup>[1](#d7)</sup><sup>, </sup><sup>[2](#change-room)</sup>
|
||||
- Spot cleaning
|
||||
- Individual spot size <sup>[1](#d7)</sup><sup>, </sup><sup>[3](#eve)</sup>
|
||||
- Clean twice <sup>[3](#eve)</sup>
|
||||
- Return to dock
|
||||
- Find the robot
|
||||
- Schedule (de)activation
|
||||
- Robot information
|
||||
- Battery level
|
||||
- Charging state
|
||||
- Dock occupancy
|
||||
- Model and firmware version
|
||||
- Automatic or periodic refresh of robot state
|
||||
- Multiple robots
|
||||
- Multiple language support (en, de, fr)
|
||||
|
||||
> <b name="d7">1</b> Only available on the Neato D7.
|
||||
|
||||
> <b name="change-room">2</b> You can send the robot from one room to another as well. He will return to the base, wait there some seconds and then starts cleaning the next room.
|
||||
|
||||
> <b name="eve">3</b> You need a third party app like eve to access these features.
|
||||
|
||||
|
||||
\* Available after some seconds of cleaning.
|
||||
|
||||
## 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/).
|
||||
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
|
||||
@@ -38,20 +59,24 @@ Add the following information to your config file. Change the values for email a
|
||||
{
|
||||
"platform": "NeatoVacuumRobot",
|
||||
"email": "YourEmail",
|
||||
"password": "YourPassword"
|
||||
"password": "YourPassword",
|
||||
"language": "de"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Advanced
|
||||
|
||||
The following config contains advanced optional settings that are off when not specified.
|
||||
Below are explanations for advanced parameters to adjust the plugin to your needs. All parameters are *optional*.
|
||||
|
||||
The parameter **refresh** sets 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).
|
||||
**refresh**
|
||||
Timer for periodic refresh of robot state. The default is `auto`. The options are:
|
||||
`auto` Updates the robot state when a cleaning was started via homekit so that you can activate automations based on a successful cleaning.
|
||||
`120` Or any other time in seconds (minimum `60`) is required if you want to receive robot state updates after starting the cleaning from outside of homekit (e.g. neato app or schedule).
|
||||
`0` Disables background updates completely.
|
||||
|
||||
The parameter **extraCareNavigation** sets if supporting models (currently Neato D3 and D5) should take extra care of your furniture while cleaning.
|
||||
|
||||
The parameter **disabled** accepts a list of switches/sensors that can be disabled in the neato homekit plugin (e.g. dock, dockstate, eco, schedule).
|
||||
**hidden**
|
||||
List of plugin features that you don't want to use in homekit (e.g. `dock`, `dockstate`, `eco`, `nogolines`, `extracare`, `schedule`, `find`, `spot`).
|
||||
|
||||
```json
|
||||
"platforms": [
|
||||
@@ -59,17 +84,20 @@ The parameter **disabled** accepts a list of switches/sensors that can be disabl
|
||||
"platform": "NeatoVacuumRobot",
|
||||
"email": "YourEmail",
|
||||
"password": "YourPassword",
|
||||
"language": "de",
|
||||
"refresh": "120",
|
||||
"extraCareNavigation": true,
|
||||
"disabled": ["dock", "dockstate", "eco"]
|
||||
"hidden": ["dock", "dockstate", "eco", "nogolines", "extracare", "schedule", "find", "spot"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Tested robots
|
||||
|
||||
- BotVac Connected (Firmware 2.2.0)
|
||||
- BotVac D3 Connected
|
||||
- BotVac D5 Connected
|
||||
The plugin is successfully tested with all Neato Connected Robots.
|
||||
|
||||
If you have another 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
|
||||
- [DJay](https://github.com/DJay-X) for testing out tons of new beta versions
|
||||
|
724
accessories/neatoVacuumRobot.js
Normal file
724
accessories/neatoVacuumRobot.js
Normal file
@@ -0,0 +1,724 @@
|
||||
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;
|
||||
|
||||
this.dict = {
|
||||
'en': {
|
||||
"clean": "Clean",
|
||||
"clean the": "Clean the",
|
||||
"goToDock": "Go to Dock",
|
||||
"dockState": "Dock",
|
||||
"eco": "Eco Mode",
|
||||
"noGoLines": "NoGo Lines",
|
||||
"extraCare": "Extra Care",
|
||||
"schedule": "Schedule",
|
||||
"findMe": "Find me",
|
||||
"cleanSpot": "Clean Spot",
|
||||
"battery": "Battery"
|
||||
},
|
||||
'de': {
|
||||
"clean": "Sauge",
|
||||
"clean the": "Sauge",
|
||||
"goToDock": "Zur Basis",
|
||||
"dockState": "In der Basis",
|
||||
"eco": "Eco Modus",
|
||||
"noGoLines": "NoGo Linien",
|
||||
"extraCare": "Extra Care",
|
||||
"schedule": "Zeitplan",
|
||||
"findMe": "Finde mich",
|
||||
"cleanSpot": "Spot Reinigung",
|
||||
"battery": "Batterie"
|
||||
},
|
||||
'fr': {
|
||||
"clean": "Aspirer",
|
||||
"clean the": "Aspirer",
|
||||
"goToDock": "Retour à la base",
|
||||
"dockState": "Sur la base",
|
||||
"eco": "Eco mode",
|
||||
"noGoLines": "Lignes NoGo",
|
||||
"extraCare": "Extra Care",
|
||||
"schedule": "Planifier",
|
||||
"findMe": "Me retrouver",
|
||||
"cleanSpot": "Nettoyage local",
|
||||
"battery": "Batterie"
|
||||
}
|
||||
}[this.platform.language]
|
||||
|
||||
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(this.name + " " + this.dict["battery"], "battery");
|
||||
|
||||
if (this.boundary == null)
|
||||
{
|
||||
this.cleanService = new Service.Switch(this.name + " " + this.dict["clean"], "clean");
|
||||
this.goToDockService = new Service.Switch(this.name + " " + this.dict["goToDock"], "goToDock");
|
||||
this.dockStateService = new Service.OccupancySensor(this.name + " " + this.dict["dockState"], "dockState");
|
||||
this.ecoService = new Service.Switch(this.name + " " + this.dict["eco"], "eco");
|
||||
this.noGoLinesService = new Service.Switch(this.name + " " + this.dict["noGoLines"], "noGoLines");
|
||||
this.extraCareService = new Service.Switch(this.name + " " + this.dict["extraCare"], "extraCare");
|
||||
this.scheduleService = new Service.Switch(this.name + " " + this.dict["schedule"], "schedule");
|
||||
this.findMeService = new Service.Switch(this.name + " " + this.dict["findMe"], "findMe");
|
||||
|
||||
this.spotCleanService = new Service.Switch(this.name + " " + this.dict["cleanSpot"], "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 = this.dict["clean the"] + " " + this.boundary.name;
|
||||
if (splitName.length >= 2 && splitName[splitName.length - 2].match(/[']s$/g))
|
||||
{
|
||||
serviceName = this.dict["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)
|
||||
{
|
||||
debug(this.name + ": " + (on ? "Enabled ".brightGreen : "Disabled".red) + " Clean " + (this.boundary ? JSON.stringify(this.boundary) : ''));
|
||||
this.platform.updateRobot(this.robot._serial, (error, result) =>
|
||||
{
|
||||
// Start
|
||||
if (on)
|
||||
{
|
||||
// No room given or same room
|
||||
if (this.boundary == null || this.robot.cleaningBoundaryId === this.boundary.id)
|
||||
{
|
||||
// Resume cleaning
|
||||
if (this.robot.canResume)
|
||||
{
|
||||
debug(this.name + ": ## Resume cleaning");
|
||||
this.robot.resumeCleaning((error) =>
|
||||
{
|
||||
callback(error);
|
||||
});
|
||||
}
|
||||
// Start cleaning
|
||||
else if (this.robot.canStart)
|
||||
{
|
||||
this.clean(callback);
|
||||
}
|
||||
// Cannot start
|
||||
else
|
||||
{
|
||||
debug(this.name + ": Cannot start, maybe already cleaning (expected)");
|
||||
callback();
|
||||
}
|
||||
}
|
||||
// Different room given
|
||||
else
|
||||
{
|
||||
// Return to dock
|
||||
if (this.robot.canPause || this.robot.canResume)
|
||||
{
|
||||
debug(this.name + ": ## Returning to dock to start cleaning of new room");
|
||||
this.setGoToDock(true, (error, result) =>
|
||||
{
|
||||
this.nextRoom = this.boundary.id;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
// Start new cleaning of new room
|
||||
else
|
||||
{
|
||||
debug(this.name + ": ## Start cleaning of new room");
|
||||
this.clean(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();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
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");
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
21
characteristics/spotHeight.js
Normal file
21
characteristics/spotHeight.js
Normal file
@@ -0,0 +1,21 @@
|
||||
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;
|
||||
};
|
17
characteristics/spotRepeat.js
Normal file
17
characteristics/spotRepeat.js
Normal file
@@ -0,0 +1,17 @@
|
||||
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;
|
||||
};
|
21
characteristics/spotWidth.js
Normal file
21
characteristics/spotWidth.js
Normal file
@@ -0,0 +1,21 @@
|
||||
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;
|
||||
};
|
49
config.schema.json
Normal file
49
config.schema.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"language": {
|
||||
"title": "language",
|
||||
"type": "string",
|
||||
"default": "en",
|
||||
"oneOf": [
|
||||
{
|
||||
"title": "English",
|
||||
"enum": [
|
||||
"en"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "German",
|
||||
"enum": [
|
||||
"de"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "French",
|
||||
"enum": [
|
||||
"fr"
|
||||
]
|
||||
}
|
||||
],
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
558
index.js
558
index.js
@@ -1,350 +1,306 @@
|
||||
"use strict";
|
||||
var inherits = require('util').inherits,
|
||||
let inherits = require('util').inherits,
|
||||
debug = require('debug')('homebridge-neato'),
|
||||
botvac = require('node-botvac'),
|
||||
|
||||
Service,
|
||||
Characteristic
|
||||
Characteristic,
|
||||
NeatoVacuumRobotAccessory;
|
||||
|
||||
module.exports = function (homebridge) {
|
||||
module.exports = function (homebridge)
|
||||
{
|
||||
Service = homebridge.hap.Service;
|
||||
Characteristic = homebridge.hap.Characteristic;
|
||||
NeatoVacuumRobotAccessory = require('./accessories/neatoVacuumRobot')(Service, Characteristic);
|
||||
homebridge.registerPlatform("homebridge-neato", "NeatoVacuumRobot", NeatoVacuumRobotPlatform);
|
||||
}
|
||||
};
|
||||
|
||||
function NeatoVacuumRobotPlatform(log, config) {
|
||||
function NeatoVacuumRobotPlatform(log, config)
|
||||
{
|
||||
this.log = log;
|
||||
this.serial = "1-3-3-7";
|
||||
this.email = config['email'];
|
||||
this.password = config['password'];
|
||||
this.hiddenServices = ('disabled' in config ? config['disabled'] : '');
|
||||
this.language = config['language'];
|
||||
this.hiddenServices = '';
|
||||
this.hiddenServices = ('disabled' in config ? config['disabled'] : this.hiddenServices);
|
||||
this.hiddenServices = ('hidden' in config ? config['hidden'] : this.hiddenServices);
|
||||
|
||||
this.careNavigation = ('extraCareNavigation' in config && config['extraCareNavigation'] ? 2 : 1);
|
||||
debug("Extra Care Navigation: " + this.careNavigation);
|
||||
// Array of real robots and associated robot accessories (incl rooms)
|
||||
this.robots = [];
|
||||
this.nextRoom = null;
|
||||
|
||||
// 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
|
||||
if (this.refresh > 0 && this.refresh < 60)
|
||||
{
|
||||
this.log.warn("Minimum refresh time is 60 seconds to not overload the neato servers");
|
||||
this.refresh = (this.refresh > 0 && this.refresh < 60) ? 60 : this.refresh;
|
||||
}
|
||||
}
|
||||
// default auto
|
||||
else
|
||||
{
|
||||
this.refresh = 'auto';
|
||||
}
|
||||
this.log("Refresh is set to: " + this.refresh + (this.refresh !== 'auto' ? ' seconds' : ''));
|
||||
}
|
||||
|
||||
NeatoVacuumRobotPlatform.prototype = {
|
||||
accessories: function(callback) {
|
||||
this.accessories = [];
|
||||
accessories: function (callback)
|
||||
{
|
||||
debug("Get robots");
|
||||
let accessories = [];
|
||||
this.boundaryNames = [];
|
||||
|
||||
let that = this;
|
||||
this.robots = this.getRobots(function () {
|
||||
for (var i = 0; i < that.robots.length; i++) {
|
||||
that.log("Found robot #" + (i+1) + ": " + that.robots[i].name);
|
||||
var robotAccessory = new NeatoVacuumRobotAccessory(that.robots[i], that);
|
||||
that.accessories.push(robotAccessory);
|
||||
}
|
||||
callback(that.accessories);
|
||||
this.getRobots(() =>
|
||||
{
|
||||
// // MOCK MULTIPLE ROBOTS START
|
||||
// let client = new botvac.Client();
|
||||
// client.authorize(this.email, this.password, false, (error) =>
|
||||
// {
|
||||
// client.getRobots((error, robs) =>
|
||||
// {
|
||||
// let testRobot = robs[0];
|
||||
// testRobot.getState((error, result) =>
|
||||
// {
|
||||
// testRobot.name = "Testrobot";
|
||||
// this.robots.push({device: testRobot, meta: result.meta, availableServices: result.availableServices});
|
||||
// // MOCK MULTIPLE ROBOTS END
|
||||
|
||||
this.robots.forEach((robot, i) =>
|
||||
{
|
||||
this.log("Found robot #" + (i + 1) + " named \"" + robot.device.name + "\" with serial \"" + robot.device._serial.substring(0, 9) + "XXXXXXXXXXXX\"");
|
||||
|
||||
let mainAccessory = new NeatoVacuumRobotAccessory(this, robot);
|
||||
accessories.push(mainAccessory);
|
||||
|
||||
robot.mainAccessory = mainAccessory;
|
||||
robot.roomAccessories = [];
|
||||
|
||||
// Start Update Intervall
|
||||
this.updateRobotTimer(robot.device._serial);
|
||||
|
||||
// // MOCK ZONE CLEANING START
|
||||
// robot.boundary = {name: "Testroom", id: "1"};
|
||||
// let roomAccessory = new NeatoVacuumRobotAccessory(this, robot);
|
||||
// accessories.push(roomAccessory);
|
||||
// robot.roomAccessories.push(roomAccessory);
|
||||
// // MOCK ZONE CLEANING END
|
||||
|
||||
if (robot.device.maps)
|
||||
{
|
||||
robot.device.maps.forEach((map) =>
|
||||
{
|
||||
if (map.boundaries)
|
||||
{
|
||||
map.boundaries.forEach((boundary) =>
|
||||
{
|
||||
if (boundary.type === "polygon")
|
||||
{
|
||||
robot.boundary = boundary;
|
||||
let roomAccessory = new NeatoVacuumRobotAccessory(this, robot);
|
||||
accessories.push(roomAccessory);
|
||||
|
||||
robot.roomAccessories.push(roomAccessory);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
callback(accessories);
|
||||
|
||||
// // MOCK MULTIPLE ROBOTS START
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// // MOCK MULTIPLE ROBOTS END
|
||||
});
|
||||
},
|
||||
|
||||
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) {
|
||||
if (error) {
|
||||
that.log(error);
|
||||
that.log.error("Can't log on to neato cloud. Please check your credentials.");
|
||||
|
||||
// Login
|
||||
client.authorize(this.email, this.password, false, (error) =>
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
this.log.error("Can't log on to neato cloud. Please check your internet connection and your credentials. Try again later if the neato servers have issues: " + error);
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
client.getRobots(function (error, robots) {
|
||||
if (error) {
|
||||
that.log(error);
|
||||
that.log.error("Successful login but can't connect to your neato robot.");
|
||||
else
|
||||
{
|
||||
// Get all robots
|
||||
client.getRobots((error, robots) =>
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
this.log.error("Successful login but can't connect to your neato robot: " + error);
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
if (robots.length === 0) {
|
||||
that.log.error("Successful login but no robots associated with your account.");
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
that.robots = robots;
|
||||
callback();
|
||||
}
|
||||
else if (robots.length === 0)
|
||||
{
|
||||
this.log.error("Successful login but no robots associated with your account.");
|
||||
this.robots = [];
|
||||
callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Found " + robots.length + " robots");
|
||||
let loadedRobots = 0;
|
||||
|
||||
robots.forEach((robot) =>
|
||||
{
|
||||
// Get additional information for the robot
|
||||
robot.getState((error, state) =>
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
this.log.error("Error getting robot meta information: " + error + ": " + state);
|
||||
callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get all maps for each robot
|
||||
robot.getPersistentMaps((error, maps) =>
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
this.log.error("Error updating persistent maps: " + error + ": " + maps);
|
||||
callback();
|
||||
}
|
||||
// Robot has no maps
|
||||
else if (maps.length === 0)
|
||||
{
|
||||
robot.maps = [];
|
||||
this.robots.push({device: robot, meta: state.meta, availableServices: state.availableServices});
|
||||
loadedRobots++;
|
||||
if (loadedRobots === robots.length)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
// Robot has maps
|
||||
else
|
||||
{
|
||||
robot.maps = maps;
|
||||
let loadedMaps = 0;
|
||||
robot.maps.forEach((map) =>
|
||||
{
|
||||
// Save zones in each map
|
||||
robot.getMapBoundaries(map.id, (error, result) =>
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
this.log.error("Error getting boundaries: " + error + ": " + result)
|
||||
}
|
||||
else
|
||||
{
|
||||
map.boundaries = result.boundaries;
|
||||
}
|
||||
loadedMaps++;
|
||||
|
||||
// Robot is completely requested if zones for all maps are loaded
|
||||
if (loadedMaps === robot.maps.length)
|
||||
{
|
||||
this.robots.push({device: robot, meta: state.meta, availableServices: state.availableServices});
|
||||
loadedRobots++;
|
||||
if (loadedRobots === robots.length)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function NeatoVacuumRobotAccessory(robot, platform) {
|
||||
this.platform = platform;
|
||||
this.log = platform.log;
|
||||
this.refresh = platform.refresh;
|
||||
this.careNavigation = platform.careNavigation;
|
||||
this.hiddenServices = platform.hiddenServices;
|
||||
this.robot = robot;
|
||||
this.name = robot.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();
|
||||
}
|
||||
|
||||
|
||||
NeatoVacuumRobotAccessory.prototype = {
|
||||
identify: function (callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function() {
|
||||
// hide serial and secret in log
|
||||
let _serial = that.robot._serial;
|
||||
let _secret = that.robot._secret;
|
||||
that.robot._serial = "*****";
|
||||
that.robot._secret = "*****";
|
||||
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)
|
||||
.setCharacteristic(Characteristic.Manufacturer, "Neato Robotics")
|
||||
.setCharacteristic(Characteristic.Model, "Coming soon")
|
||||
.setCharacteristic(Characteristic.SerialNumber, this.robot._serial);
|
||||
updateRobot: function (serial, callback)
|
||||
{
|
||||
let robot = this.getRobot(serial);
|
||||
|
||||
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('set', this.setClean.bind(this));
|
||||
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('get', this.getClean.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.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.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 = [this.informationService, this.vacuumRobotCleanService, 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('schedule') === -1)
|
||||
this.services.push(this.vacuumRobotScheduleService);
|
||||
|
||||
return this.services;
|
||||
},
|
||||
|
||||
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 (that.robot.canResume) {
|
||||
debug(that.name + ": Resume cleaning");
|
||||
that.robot.resumeCleaning(callback);
|
||||
}
|
||||
else {
|
||||
debug(that.name + ": Start cleaning (" + that.careNavigation + ")");
|
||||
that.robot.startCleaning(that.robot.eco, that.careNavigation, 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setGoToDock: function (on, callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function (error, result) {
|
||||
if (on) {
|
||||
if (that.robot.canPause) {
|
||||
debug(that.name + ": 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(that.name + ": Go to dock");
|
||||
that.robot.sendToBase(callback);
|
||||
}
|
||||
else {
|
||||
debug(that.name + ": Can't go to dock at the moment");
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setEco: function (on, callback) {
|
||||
debug(this.name + ": " + (on ? "Enable eco mode" : "Disable eco mode"));
|
||||
this.robot.eco = on;
|
||||
callback();
|
||||
},
|
||||
|
||||
setSchedule: function (on, callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function (error, result) {
|
||||
if (on) {
|
||||
debug(that.name + ": Enable schedule");
|
||||
that.robot.enableSchedule(callback);
|
||||
}
|
||||
else {
|
||||
debug(that.name + ": Disable schedule");
|
||||
that.robot.disableSchedule(callback);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getClean: function(callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function (error, result) {
|
||||
debug(that.name + ": Is cleaning: " + that.robot.canPause);
|
||||
callback(false, that.robot.canPause);
|
||||
});
|
||||
},
|
||||
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
getDock: function(callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function (error, result) {
|
||||
debug(that.name + ": Is docked: " + that.robot.isDocked);
|
||||
callback(false, that.robot.isDocked);
|
||||
});
|
||||
},
|
||||
|
||||
getEco: function(callback) {
|
||||
// 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.updateRobot(function (error, result) {
|
||||
debug(that.name + ": Schedule: " + that.robot.isScheduleEnabled);
|
||||
callback(false, that.robot.isScheduleEnabled);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
getBatteryLevel: function(callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function (error, result) {
|
||||
debug(that.name + ": Battery: " + that.robot.charge);
|
||||
callback(false, that.robot.charge);
|
||||
});
|
||||
},
|
||||
|
||||
getBatteryChargingState: function(callback) {
|
||||
let that = this;
|
||||
this.updateRobot(function (error, result) {
|
||||
debug(that.name + ": Is charging: " + that.robot.isCharging);
|
||||
callback(false, that.robot.isCharging);
|
||||
});
|
||||
},
|
||||
|
||||
updateRobot: function(callback) {
|
||||
let that = this;
|
||||
if (this.lastUpdate !== null && new Date() - this.lastUpdate < 2000) {
|
||||
debug(this.name + ": Update (cached)");
|
||||
// Data is up to date
|
||||
if (typeof (robot.lastUpdate) !== 'undefined' && new Date() - robot.lastUpdate < 2000)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
debug(this.name + ": Update (online)");
|
||||
this.robot.getState(function (error, result) {
|
||||
that.lastUpdate = new Date();
|
||||
else
|
||||
{
|
||||
debug(robot.device.name + ": ++ Updating robot state");
|
||||
robot.lastUpdate = new Date();
|
||||
robot.device.getState((error, result) =>
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
this.log.error("Cannot update robot. Check if robot is online. " + error);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateRobotTimer: function() {
|
||||
let that = this;
|
||||
debug(this.name + ": Timer called");
|
||||
this.updateRobot(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);
|
||||
getRobot(serial)
|
||||
{
|
||||
let result;
|
||||
this.robots.forEach(function (robot)
|
||||
{
|
||||
if (robot.device._serial === serial)
|
||||
{
|
||||
result = robot;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
if (that.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).value !== !that.robot.dockHasBeenSeen) {
|
||||
that.vacuumRobotGoToDockService.setCharacteristic(Characteristic.On, !that.robot.dockHasBeenSeen);
|
||||
updateRobotTimer: function (serial)
|
||||
{
|
||||
this.updateRobot(serial, () =>
|
||||
{
|
||||
let robot = this.getRobot(serial);
|
||||
// Clear any other overlapping timers for this robot
|
||||
clearTimeout(robot.timer);
|
||||
|
||||
// Tell all accessories of this robot (mainAccessory and roomAccessories) that updated robot data is available
|
||||
robot.mainAccessory.updated();
|
||||
robot.roomAccessories.forEach(accessory =>
|
||||
{
|
||||
accessory.updated();
|
||||
});
|
||||
|
||||
// Periodic refresh interval set in config
|
||||
if (this.refresh !== 'auto' && this.refresh !== 0)
|
||||
{
|
||||
debug(robot.device.name + ": ++ Next background update in " + this.refresh + " seconds");
|
||||
robot.timer = setTimeout(this.updateRobotTimer.bind(this), this.refresh * 1000, serial);
|
||||
}
|
||||
|
||||
if (that.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).value !== that.robot.isScheduleEnabled) {
|
||||
that.vacuumRobotScheduleService.setCharacteristic(Characteristic.On, that.robot.isScheduleEnabled);
|
||||
// Auto refresh set in config
|
||||
else if (this.refresh === 'auto' && robot.device.canPause)
|
||||
{
|
||||
debug(robot.device.name + ": ++ Next background update in 60 seconds while cleaning (auto mode)");
|
||||
robot.timer = setTimeout(this.updateRobotTimer.bind(this), 60 * 1000, serial);
|
||||
}
|
||||
|
||||
// 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(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");
|
||||
// No refresh
|
||||
else
|
||||
{
|
||||
debug(robot.device.name + ": ++ Stopped background updates");
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
25
package.json
25
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "homebridge-neato",
|
||||
"version": "0.4.4",
|
||||
"version": "0.7.3",
|
||||
"description": "A Neato vacuum robot plugin for homebridge.",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@@ -13,14 +13,31 @@
|
||||
"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"
|
||||
"colors": "^1.4.0",
|
||||
"debug": "^4.1.1",
|
||||
"node-botvac": ">=0.4.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user