Compare commits
No commits in common. "master" and "v0.7.0-beta.0" have entirely different histories.
master
...
v0.7.0-bet
19
.github/workflows/npm.yml
vendored
19
.github/workflows/npm.yml
vendored
@ -1,19 +0,0 @@
|
|||||||
name: npm
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
# Setup .npmrc file to publish to npm
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '12.x'
|
|
||||||
registry-url: 'https://registry.npmjs.org'
|
|
||||||
- run: npm install
|
|
||||||
- run: npm publish
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -104,32 +104,6 @@
|
|||||||
|
|
||||||
## 0.7.0
|
## 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 taking eco and extraCare mode into account
|
||||||
* Fixed room switches not supporting pause/resume
|
* Fixed room switches to support pause/resume of cleaning
|
||||||
|
* Added feature that enabling another room switch, returns to robot to dock and starts cleaning the new room automatically
|
||||||
## 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.8.0
|
|
||||||
* Add German plugin language (for example, this gives you a "Sauge Küche" Siri command for a zone called "Küche")
|
|
||||||
* Added possibility to toggle between languages (English/German) in Homebridge UI Plugin Settings
|
|
||||||
|
|
||||||
## 0.8.1
|
|
||||||
* Include Robot name in Homekit battery service name
|
|
||||||
|
|
||||||
## 0.8.2
|
|
||||||
* Eliminate warnings on Homebridge >= 1.3.0 (77945f8 and 877c3d7 on `naofireblade/homebridge-neato`)
|
|
||||||
|
|
||||||
## 0.8.3
|
|
||||||
* Add French plugin language (for example, this gives you a "Aspirer la cuisine" Siri command for a zone called "La cuisine")
|
|
||||||
|
|
||||||
## 0.8.4
|
|
||||||
* Link to token getter tool in homebridge UI
|
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2020 Luis Riegger
|
Copyright (c) 2017 Arne Blumentritt
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
146
README.md
146
README.md
@ -1,131 +1,85 @@
|
|||||||
[](https://www.npmjs.com/package/homebridge-kobold)
|
# homebridge-neato
|
||||||
[](https://www.npmjs.com/package/homebridge-kobold?activeTab=versions)
|
[](https://www.npmjs.com/package/homebridge-neato)
|
||||||
|
[](https://www.npmjs.com/package/homebridge-neato)
|
||||||
|
[](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).
|
||||||
|
|
||||||
# homebridge-kobold
|
If you like this plugin, I would be very grateful for your support:
|
||||||
|
|
||||||
This is a plugin for [homebridge](https://github.com/nfarina/homebridge) to control your [Vorwerk Kobold](https://kobold.vorwerk.de/saugroboter/) VR300 vacuum robot. You can download it via [npm](https://www.npmjs.com/package/homebridge-kobold).
|
<a href="https://www.buymeacoffee.com/2D1nUuK36" 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>
|
||||||
|
|
||||||
It is based on a fork of naofireblade's [homebridge-neato](https://github.com/naofireblade/homebridge-neato), merged with the oAuth authentication mechanism from nicoh88's [homebridge-vorwerk](https://github.com/nicoh88/homebridge-vorwerk).
|
Feel free to leave any feedback [here](https://github.com/naofireblade/homebridge-neato/issues).
|
||||||
|
|
||||||
The interaction with the Server is handled by the underlying [node-kobold-control](https://github.com/himbeles/node-kobold-control) module.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- House Cleaning
|
- Start and pause cleaning
|
||||||
- Eco mode
|
|
||||||
- Extra care navigation
|
|
||||||
- Nogo lines
|
|
||||||
- Zone cleaning <sup>[1](#change-room)</sup>
|
|
||||||
- Spot cleaning
|
|
||||||
- Individual spot size <sup>[2](#eve)</sup>
|
|
||||||
- Clean twice <sup>[2](#eve)</sup>
|
|
||||||
- Return to dock
|
- Return to dock
|
||||||
- Find the robot
|
- Scheduling
|
||||||
- Schedule (de)activation
|
- Eco mode
|
||||||
- Robot information
|
- Extra care navigation
|
||||||
- Battery level
|
- Nogo lines
|
||||||
- Charging state
|
- Zone cleaning
|
||||||
- Dock occupancy
|
- Get battery info
|
||||||
- Model and firmware version
|
- Get dock info
|
||||||
- Automatic or periodic refresh of robot state
|
- Periodic refresh of robot state
|
||||||
- Multiple robots
|
- Support for multiple robots
|
||||||
|
|
||||||
- German, English or French Language Setting
|
|
||||||
|
|
||||||
> <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.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Install homebridge using: `npm install -g homebridge`
|
1. Install homebridge using: `npm install -g homebridge`
|
||||||
2. Install this plugin using: `npm install -g homebridge-kobold`
|
2. Install this plugin using: `npm install -g homebridge-neato`
|
||||||
3. Update your configuration file. See the sample below.
|
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. Adapt the value for `token`.
|
Add the following information to your config file. Change the values for email and password.
|
||||||
|
|
||||||
### Simple
|
### Simple
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"platforms": [
|
"platforms": [
|
||||||
{
|
{
|
||||||
"platform": "KoboldVacuumRobot",
|
"platform": "NeatoVacuumRobot",
|
||||||
"token": "YourToken",
|
"email": "YourEmail",
|
||||||
"language": "de"
|
"password": "YourPassword"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
You can get a token using the GUI tool [Kobold Token Getter](https://github.com/himbeles/kobold-token-get) or using the following two curl commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# This will trigger the email sending
|
|
||||||
curl -X "POST" "https://mykobold.eu.auth0.com/passwordless/start" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{
|
|
||||||
"send": "code",
|
|
||||||
"email": "ENTER_YOUR_EMAIL_HERE",
|
|
||||||
"client_id": "KY4YbVAvtgB7lp8vIbWQ7zLk3hssZlhR",
|
|
||||||
"connection": "email"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
==== wait for the email to be received ====
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# this will generate a token using the numbers you received via email
|
|
||||||
# replace the value of otp 123456 with the value you received from the email
|
|
||||||
curl -X "POST" "https://mykobold.eu.auth0.com/oauth/token" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{
|
|
||||||
"prompt": "login",
|
|
||||||
"grant_type": "http://auth0.com/oauth/grant-type/passwordless/otp",
|
|
||||||
"scope": "openid email profile read:current_user",
|
|
||||||
"locale": "en",
|
|
||||||
"otp": "123456",
|
|
||||||
"source": "vorwerk_auth0",
|
|
||||||
"platform": "ios",
|
|
||||||
"audience": "https://mykobold.eu.auth0.com/userinfo",
|
|
||||||
"username": "ENTER_YOUR_EMAIL_HERE",
|
|
||||||
"client_id": "KY4YbVAvtgB7lp8vIbWQ7zLk3hssZlhR",
|
|
||||||
"realm": "email",
|
|
||||||
"country_code": "DE"
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
From the output, you want to copy the `id_token` value.
|
|
||||||
|
|
||||||
The `language` can be `de` for German, `en` for English, or `fr` for French.
|
|
||||||
|
|
||||||
### Advanced
|
### Advanced
|
||||||
|
|
||||||
Below are explanations for advanced parameters to adjust the plugin to your needs. All parameters are *optional*.
|
The following config contains advanced optional settings.
|
||||||
|
|
||||||
**refresh**
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
**hidden**
|
The parameter **disabled** accepts a list of switches/sensors that can be disabled in the neato homekit plugin (e.g. dock, dockstate, eco, schedule).
|
||||||
List of plugin features that you don't want to use in homekit (e.g. `dock`, `dockstate`, `eco`, `nogolines`, `extracare`, `schedule`, `find`, `spot`).
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"platforms": [
|
"platforms": [
|
||||||
{
|
{
|
||||||
"platform": "KoboldVacuumRobot",
|
"platform": "NeatoVacuumRobot",
|
||||||
"token": "YourToken",
|
"email": "YourEmail",
|
||||||
"refresh": "120",
|
"password": "YourPassword",
|
||||||
"hidden": ["dock", "dockstate", "eco", "nogolines", "extracare", "schedule", "find", "spot"],
|
"refresh": "120",
|
||||||
"language": "de"
|
"disabled": ["dock", "dockstate", "eco", "nogolines", "extracare", "schedule"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tested robots
|
## Tested robots
|
||||||
|
|
||||||
- Vorwerk Kobold VR300
|
- BotVac Connected (Firmware 2.2.0)
|
||||||
|
- BotVac D3 Connected
|
||||||
|
- BotVac D5 Connected (Firmware 4.0.0, 4.3.0)
|
||||||
|
- BotVac D7 Connected
|
||||||
|
|
||||||
|
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
|
||||||
|
- [DJay](https://github.com/DJay-X) for testing new beta versions
|
1
_config.yml
Normal file
1
_config.yml
Normal file
@ -0,0 +1 @@
|
|||||||
|
theme: jekyll-theme-cayman
|
@ -1,726 +0,0 @@
|
|||||||
const debug = require('debug')('homebridge-kobold');
|
|
||||||
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 KoboldVacuumRobotAccessory;
|
|
||||||
};
|
|
||||||
|
|
||||||
function KoboldVacuumRobotAccessory(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.cleanService = new Service.Switch(serviceName + "1", "cleanBoundary:" + this.boundary.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.log("Added cleaning device named: " + this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
KoboldVacuumRobotAccessory.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, "Vorwerk Deutschland Stiftung & Co. KG")
|
|
||||||
.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)
|
|
||||||
{
|
|
||||||
debug(this.name + ": ## Start cleaning");
|
|
||||||
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");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
570
accessories/neatVacuumRobot.js
Normal file
570
accessories/neatVacuumRobot.js
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
const debug = require('debug')('homebridge-neato');
|
||||||
|
|
||||||
|
let Service,
|
||||||
|
Characteristic;
|
||||||
|
|
||||||
|
module.exports = function (_Service, _Characteristic)
|
||||||
|
{
|
||||||
|
Service = _Service;
|
||||||
|
Characteristic = _Characteristic;
|
||||||
|
|
||||||
|
return NeatoVacuumRobotAccessory;
|
||||||
|
};
|
||||||
|
|
||||||
|
function NeatoVacuumRobotAccessory(robot, platform, boundary = undefined)
|
||||||
|
{
|
||||||
|
this.platform = platform;
|
||||||
|
this.boundary = boundary;
|
||||||
|
this.log = platform.log;
|
||||||
|
this.refresh = platform.refresh;
|
||||||
|
this.hiddenServices = platform.hiddenServices;
|
||||||
|
this.robot = robot;
|
||||||
|
this.nextRoom = null;
|
||||||
|
|
||||||
|
if (typeof boundary === 'undefined')
|
||||||
|
{
|
||||||
|
this.name = 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.lastUpdate = null;
|
||||||
|
|
||||||
|
this.vacuumRobotBatteryService = new Service.BatteryService("Battery", "battery");
|
||||||
|
|
||||||
|
if (typeof boundary === 'undefined')
|
||||||
|
{
|
||||||
|
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 ()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getServices: function ()
|
||||||
|
{
|
||||||
|
this.informationService = new Service.AccessoryInformation();
|
||||||
|
this.informationService
|
||||||
|
.setCharacteristic(Characteristic.Manufacturer, "Neato Robotics")
|
||||||
|
.setCharacteristic(Characteristic.Model, "Coming soon")
|
||||||
|
.setCharacteristic(Characteristic.SerialNumber, this.robot._serial);
|
||||||
|
if (typeof this.boundary === "undefined")
|
||||||
|
{
|
||||||
|
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 (typeof this.boundary === "undefined")
|
||||||
|
{
|
||||||
|
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('set', (on, serviceCallback) =>
|
||||||
|
{
|
||||||
|
this.setClean(on, serviceCallback, this.boundary)
|
||||||
|
});
|
||||||
|
this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('get', (serviceCallback) =>
|
||||||
|
{
|
||||||
|
this.getClean(serviceCallback, this.boundary);
|
||||||
|
});
|
||||||
|
|
||||||
|
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.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.services.push(this.vacuumRobotCleanService);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.vacuumRobotCleanBoundaryService.getCharacteristic(Characteristic.On).on('set', (on, serviceCallback) =>
|
||||||
|
{
|
||||||
|
this.setClean(on, serviceCallback, this.boundary)
|
||||||
|
});
|
||||||
|
this.vacuumRobotCleanBoundaryService.getCharacteristic(Characteristic.On).on('get', (serviceCallback) =>
|
||||||
|
{
|
||||||
|
this.getClean(serviceCallback, this.boundary);
|
||||||
|
});
|
||||||
|
this.services.push(this.vacuumRobotCleanBoundaryService);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.services;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getClean: function (callback, boundary)
|
||||||
|
{
|
||||||
|
this.updateRobot((error, result) =>
|
||||||
|
{
|
||||||
|
let cleaning;
|
||||||
|
if (typeof boundary === 'undefined')
|
||||||
|
{
|
||||||
|
cleaning = this.robot.canPause;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cleaning = this.robot.canPause && (this.robot.cleaningBoundaryId === boundary.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(this.name + ": Cleaning is " + (cleaning ? 'ON' : 'OFF'));
|
||||||
|
callback(false, cleaning);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setClean: function (on, callback, boundary)
|
||||||
|
{
|
||||||
|
this.updateRobot((error, result) =>
|
||||||
|
{
|
||||||
|
// Start
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
debug(typeof boundary);
|
||||||
|
debug(boundary);
|
||||||
|
// No room given or same room
|
||||||
|
if (typeof boundary === 'undefined' || this.robot.cleaningBoundaryId === boundary.id)
|
||||||
|
{
|
||||||
|
// Resume cleaning
|
||||||
|
if (this.robot.canResume)
|
||||||
|
{
|
||||||
|
debug(this.name + ": Resume cleaning");
|
||||||
|
this.robot.resumeCleaning(callback);
|
||||||
|
}
|
||||||
|
// Start cleaning
|
||||||
|
else if (this.robot.canStart)
|
||||||
|
{
|
||||||
|
this.clean(callback, boundary);
|
||||||
|
}
|
||||||
|
// Cannot start
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(this.name + ": Cannot start, maybe already cleaning");
|
||||||
|
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 = boundary;
|
||||||
|
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
this.clean(callback, boundary);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Start new cleaning of new room
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.clean(callback, boundary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Stop
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.robot.canPause)
|
||||||
|
{
|
||||||
|
debug(this.name + ": Pause cleaning");
|
||||||
|
this.robot.pauseCleaning(callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(this.name + ": Already paused");
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: function (callback, boundary)
|
||||||
|
{
|
||||||
|
// Start automatic update while cleaning
|
||||||
|
if (this.refresh === 'auto')
|
||||||
|
{
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.updateRobotTimer();
|
||||||
|
}, 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let eco = this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).value;
|
||||||
|
let extraCare = this.vacuumRobotExtraCareService.getCharacteristic(Characteristic.On).value;
|
||||||
|
let nogoLines = this.vacuumRobotNoGoLinesService.getCharacteristic(Characteristic.On).value;
|
||||||
|
let room = (typeof boundary === 'undefined') ? '' : boundary.name;
|
||||||
|
debug(this.name + ": Start cleaning (" + room + " eco: " + eco + ", extraCare: " + extraCare + ", nogoLines: " + nogoLines + ")");
|
||||||
|
|
||||||
|
// Normal cleaning
|
||||||
|
if (typeof boundary === 'undefined')
|
||||||
|
{
|
||||||
|
this.robot.startCleaning(
|
||||||
|
eco,
|
||||||
|
extraCare ? 2 : 1,
|
||||||
|
nogoLines,
|
||||||
|
(error, result) =>
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
this.log.error("Cannot start cleaning. " + error + ": " + JSON.stringify(result));
|
||||||
|
callback(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Room cleaning
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.robot.startCleaningBoundary(eco, extraCare, boundary.id, (error, result) =>
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
this.log.error("Cannot start room cleaning. " + error + ": " + JSON.stringify(result));
|
||||||
|
callback(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getGoToDock: function (callback)
|
||||||
|
{
|
||||||
|
callback(false, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
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(that.name + ": Go to dock");
|
||||||
|
that.robot.sendToBase(callback);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (that.robot.canGoToBase)
|
||||||
|
{
|
||||||
|
debug(that.name + ": Go to dock");
|
||||||
|
that.robot.sendToBase(callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
that.log.warn(that.name + ": Can't go to dock at the moment");
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getEco: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Eco mode is " + (that.robot.eco ? 'ON' : 'OFF'));
|
||||||
|
callback(false, that.robot.eco);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setEco: function (on, callback)
|
||||||
|
{
|
||||||
|
this.robot.eco = on;
|
||||||
|
debug(this.name + ": " + (on ? "Enabled" : "Disabled") + " Eco mode ");
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
getNoGoLines: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Nogo Lines are " + (that.robot.eco ? 'ON' : 'OFF'));
|
||||||
|
callback(false, that.robot.noGoLines ? 1 : 0);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setNoGoLines: function (on, callback)
|
||||||
|
{
|
||||||
|
this.robot.noGoLines = on;
|
||||||
|
debug(this.name + ": " + (on ? "Enabled" : "Disabled") + " Nogo lines ");
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
getExtraCare: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Extra Care Navigation is " + (that.robot.navigationMode == 2 ? 'ON' : 'OFF'));
|
||||||
|
callback(false, that.robot.navigationMode == 2 ? 1 : 0);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setExtraCare: function (on, callback)
|
||||||
|
{
|
||||||
|
this.robot.navigationMode = on ? 2 : 1;
|
||||||
|
debug(this.name + ": " + (on ? "Enabled" : "Disabled") + " Extra Care Navigation ");
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
getSchedule: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Schedule is " + (that.robot.eco ? 'ON' : 'OFF'));
|
||||||
|
callback(false, that.robot.isScheduleEnabled);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setSchedule: function (on, callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function (error, result)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
debug(that.name + ": Enabled Schedule");
|
||||||
|
that.robot.enableSchedule(callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(that.name + ": Disabled Schedule");
|
||||||
|
that.robot.disableSchedule(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getDock: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Is " + (that.robot.isDocked ? '' : 'not ') + "docked");
|
||||||
|
callback(false, that.robot.isDocked ? 1 : 0);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getBatteryLevel: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Battery is at " + that.robot.charge + "%");
|
||||||
|
callback(false, that.robot.charge);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getBatteryChargingState: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
this.updateRobot(function ()
|
||||||
|
{
|
||||||
|
debug(that.name + ": Is " + (that.robot.isCharging ? '' : 'not ') + "charging");
|
||||||
|
callback(false, that.robot.isCharging);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateRobot: function (callback)
|
||||||
|
{
|
||||||
|
let that = this;
|
||||||
|
if (this.lastUpdate !== null && new Date() - this.lastUpdate < 2000)
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(this.name + ": Updating robot state");
|
||||||
|
this.robot.getState(function (error, result)
|
||||||
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
that.log.error("Cannot update robot. Check if robot is online. " + error);
|
||||||
|
}
|
||||||
|
that.lastUpdate = new Date();
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateRobotTimer: function ()
|
||||||
|
{
|
||||||
|
this.updateRobot((error, result) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!this.boundary)
|
||||||
|
{
|
||||||
|
// only update these values if the state is different from the current one, otherwise we might accidentally start an action
|
||||||
|
if (this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).value !== this.robot.canPause)
|
||||||
|
{
|
||||||
|
this.vacuumRobotCleanService.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.vacuumRobotGoToDockService.getCharacteristic(Characteristic.On).value == true && this.robot.dockHasBeenSeen)
|
||||||
|
{
|
||||||
|
this.vacuumRobotGoToDockService.setCharacteristic(Characteristic.On, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).value !== this.robot.isScheduleEnabled)
|
||||||
|
{
|
||||||
|
this.vacuumRobotScheduleService.setCharacteristic(Characteristic.On, this.robot.isScheduleEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no commands here, values can be updated without problems
|
||||||
|
this.vacuumRobotDockStateService.setCharacteristic(Characteristic.OccupancyDetected, this.robot.isDocked ? 1 : 0);
|
||||||
|
this.vacuumRobotEcoService.setCharacteristic(Characteristic.On, this.robot.eco);
|
||||||
|
this.vacuumRobotNoGoLinesService.setCharacteristic(Characteristic.On, this.robot.noGoLines);
|
||||||
|
this.vacuumRobotExtraCareService.setCharacteristic(Characteristic.On, this.robot.navigationMode == 2 ? true : false);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.vacuumRobotCleanBoundaryService.getCharacteristic(Characteristic.On).value !== this.robot.canPause)
|
||||||
|
{
|
||||||
|
this.vacuumRobotCleanBoundaryService.setCharacteristic(Characteristic.On, this.robot.canPause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vacuumRobotBatteryService.setCharacteristic(Characteristic.BatteryLevel, this.robot.charge);
|
||||||
|
this.vacuumRobotBatteryService.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;
|
||||||
|
}, this.nextRoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// robot is currently cleaning, refresh is set to auto or specific interval -> continue updating
|
||||||
|
if (this.robot.canPause && this.refresh !== 0)
|
||||||
|
{
|
||||||
|
let refreshTime = this.refresh === 'auto' ? 60 : this.refresh;
|
||||||
|
debug(this.name + ": Updating state in background every " + refreshTime + " seconds while cleaning");
|
||||||
|
this.timer = setTimeout(this.updateRobotTimer.bind(this), refreshTime * 1000);
|
||||||
|
}
|
||||||
|
// robot is not cleaning, but a specific refresh interval is set -> continue updating
|
||||||
|
else if (this.refresh !== 'auto' && this.refresh !== 0)
|
||||||
|
{
|
||||||
|
debug(this.name + ": Updating state in background every " + this.refresh + " seconds (user setting)");
|
||||||
|
this.timer = setTimeout(this.updateRobotTimer.bind(this), this.refresh * 1000);
|
||||||
|
}
|
||||||
|
// robot is not cleaning, no specific refresh interval is set -> stop updating
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(this.name + ": Disabled Background Updates");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
@ -1,21 +0,0 @@
|
|||||||
const inherits = require('util').inherits;
|
|
||||||
|
|
||||||
module.exports = function (Characteristic, CustomUUID)
|
|
||||||
{
|
|
||||||
let SpotHeight = function ()
|
|
||||||
{
|
|
||||||
Characteristic.call(this, 'Spot ↕', CustomUUID.SpotCleanHeight);
|
|
||||||
this.setProps({
|
|
||||||
format: Characteristic.Formats.INT,
|
|
||||||
unit: 'cm',
|
|
||||||
maxValue: 400,
|
|
||||||
minValue: 100,
|
|
||||||
minStep: 50,
|
|
||||||
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE]
|
|
||||||
});
|
|
||||||
this.value = this.getDefaultValue();
|
|
||||||
};
|
|
||||||
inherits(SpotHeight, Characteristic);
|
|
||||||
|
|
||||||
return SpotHeight;
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
const inherits = require('util').inherits;
|
|
||||||
|
|
||||||
module.exports = function (Characteristic, CustomUUID)
|
|
||||||
{
|
|
||||||
let SpotRepeat = function ()
|
|
||||||
{
|
|
||||||
Characteristic.call(this, 'Spot 2x', CustomUUID.SpotCleanRepeat);
|
|
||||||
this.setProps({
|
|
||||||
format: Characteristic.Formats.BOOL,
|
|
||||||
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE]
|
|
||||||
});
|
|
||||||
this.value = this.getDefaultValue();
|
|
||||||
};
|
|
||||||
inherits(SpotRepeat, Characteristic);
|
|
||||||
|
|
||||||
return SpotRepeat;
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
const inherits = require('util').inherits;
|
|
||||||
|
|
||||||
module.exports = function (Characteristic, CustomUUID)
|
|
||||||
{
|
|
||||||
let SpotWidth = function ()
|
|
||||||
{
|
|
||||||
Characteristic.call(this, 'Spot ↔', CustomUUID.SpotCleanWidth);
|
|
||||||
this.setProps({
|
|
||||||
format: Characteristic.Formats.INT,
|
|
||||||
unit: 'cm',
|
|
||||||
maxValue: 400,
|
|
||||||
minValue: 100,
|
|
||||||
minStep: 50,
|
|
||||||
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE]
|
|
||||||
});
|
|
||||||
this.value = this.getDefaultValue();
|
|
||||||
};
|
|
||||||
inherits(SpotWidth, Characteristic);
|
|
||||||
|
|
||||||
return SpotWidth;
|
|
||||||
};
|
|
@ -1,42 +1,23 @@
|
|||||||
{
|
{
|
||||||
"pluginAlias": "KoboldVacuumRobot",
|
"pluginAlias": "NeatoVacuumRobot",
|
||||||
"pluginType": "platform",
|
"pluginType": "platform",
|
||||||
"headerDisplay": "For Advanced settings like the refresh time interval or disabled switches/sensors. [Check Here](https://github.com/himbeles/homebridge-kobold#readme)",
|
"headerDisplay": "For Advanced settings like Refresh time interval or Disabled switches/sensors. [Check Here](https://github.com/naofireblade/homebridge-neato#readme)",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"token": {
|
"email": {
|
||||||
"title": "token",
|
"title": "email",
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"format": "email",
|
||||||
|
"description": "Your Email Address"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"title": "password",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Your Kobold Token (https://git.io/J3g1b)"
|
"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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
317
index.js
317
index.js
@ -1,33 +1,25 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
let inherits = require('util').inherits,
|
let inherits = require('util').inherits,
|
||||||
debug = require('debug')('homebridge-kobold'),
|
debug = require('debug')('homebridge-neato'),
|
||||||
control = require('node-kobold-control'),
|
botvac = require('node-botvac'),
|
||||||
|
|
||||||
Service,
|
Service,
|
||||||
Characteristic,
|
Characteristic;
|
||||||
KoboldVacuumRobotAccessory;
|
|
||||||
|
|
||||||
module.exports = function (homebridge)
|
module.exports = function (homebridge)
|
||||||
{
|
{
|
||||||
Service = homebridge.hap.Service;
|
Service = homebridge.hap.Service;
|
||||||
Characteristic = homebridge.hap.Characteristic;
|
Characteristic = homebridge.hap.Characteristic;
|
||||||
KoboldVacuumRobotAccessory = require('./accessories/koboldVacuumRobot')(Service, Characteristic);
|
homebridge.registerPlatform("homebridge-neato", "NeatoVacuumRobot", NeatoVacuumRobotPlatform);
|
||||||
homebridge.registerPlatform("homebridge-kobold", "KoboldVacuumRobot", KoboldVacuumRobotPlatform);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function KoboldVacuumRobotPlatform(log, config)
|
function NeatoVacuumRobotPlatform(log, config)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.serial = "1-3-3-7";
|
this.serial = "1-3-3-7";
|
||||||
this.token = config['token'];
|
this.email = config['email'];
|
||||||
this.language = config['language'];
|
this.password = config['password'];
|
||||||
this.hiddenServices = '';
|
this.hiddenServices = ('disabled' in config ? config['disabled'] : '');
|
||||||
this.hiddenServices = ('disabled' in config ? config['disabled'] : this.hiddenServices);
|
|
||||||
this.hiddenServices = ('hidden' in config ? config['hidden'] : this.hiddenServices);
|
|
||||||
|
|
||||||
// Array of real robots and associated robot accessories (incl rooms)
|
|
||||||
this.robots = [];
|
|
||||||
this.nextRoom = null;
|
|
||||||
|
|
||||||
if ('refresh' in config && config['refresh'] !== 'auto')
|
if ('refresh' in config && config['refresh'] !== 'auto')
|
||||||
{
|
{
|
||||||
@ -35,271 +27,138 @@ function KoboldVacuumRobotPlatform(log, config)
|
|||||||
this.refresh = parseInt(config['refresh']);
|
this.refresh = parseInt(config['refresh']);
|
||||||
// must be integer and positive
|
// must be integer and positive
|
||||||
this.refresh = (typeof this.refresh !== 'number' || (this.refresh % 1) !== 0 || this.refresh < 0) ? 60 : this.refresh;
|
this.refresh = (typeof this.refresh !== 'number' || (this.refresh % 1) !== 0 || this.refresh < 0) ? 60 : this.refresh;
|
||||||
// minimum 60s to save some load on the Vorwerk servers
|
// minimum 60s to save some load on the neato servers
|
||||||
if (this.refresh > 0 && this.refresh < 60)
|
this.refresh = (this.refresh > 0 && this.refresh < 60) ? 60 : this.refresh;
|
||||||
{
|
|
||||||
this.log.warn("Minimum refresh time is 60 seconds to not overload the Vorwerk servers");
|
|
||||||
this.refresh = (this.refresh > 0 && this.refresh < 60) ? 60 : this.refresh;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// default auto
|
// default auto
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.refresh = 'auto';
|
this.refresh = 'auto';
|
||||||
}
|
}
|
||||||
this.log("Refresh is set to: " + this.refresh + (this.refresh !== 'auto' ? ' seconds' : ''));
|
debug("Refresh is set to: " + this.refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
KoboldVacuumRobotPlatform.prototype = {
|
NeatoVacuumRobotPlatform.prototype = {
|
||||||
accessories: function (callback)
|
accessories: function (callback)
|
||||||
{
|
{
|
||||||
debug("Get robots");
|
|
||||||
let accessories = [];
|
let accessories = [];
|
||||||
this.boundaryNames = [];
|
let platform = this;
|
||||||
|
platform.boundaryNames = [];
|
||||||
this.getRobots(() =>
|
this.getRobots(function ()
|
||||||
{
|
{
|
||||||
// // MOCK MULTIPLE ROBOTS START
|
if (platform.robots)
|
||||||
// let client = new control.Client();
|
{
|
||||||
// client.authorize(this.token, (error) =>
|
platform.robots.forEach((robot, i) =>
|
||||||
// {
|
{
|
||||||
// client.getRobots((error, robs) =>
|
platform.log("Found robot #" + (i + 1) + " named \"" + robot.name + "\" with serial \"" + robot._serial + "\"");
|
||||||
// {
|
|
||||||
// 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) =>
|
let NeatoVacuumRobotAccessory = require('./accessories/neatVacuumRobot')(Service, Characteristic);
|
||||||
|
let robotAccessory = new NeatoVacuumRobotAccessory(robot, platform);
|
||||||
|
accessories.push(robotAccessory);
|
||||||
|
|
||||||
|
if (robot.maps)
|
||||||
|
{
|
||||||
|
robot.maps.forEach((map) =>
|
||||||
{
|
{
|
||||||
this.log("Found robot #" + (i + 1) + " named \"" + robot.device.name + "\" with serial \"" + robot.device._serial.substring(0, 9) + "XXXXXXXXXXXX\"");
|
if (map.boundaries)
|
||||||
|
|
||||||
let mainAccessory = new KoboldVacuumRobotAccessory(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 KoboldVacuumRobotAccessory(this, robot);
|
|
||||||
// accessories.push(roomAccessory);
|
|
||||||
// robot.roomAccessories.push(roomAccessory);
|
|
||||||
// // MOCK ZONE CLEANING END
|
|
||||||
|
|
||||||
if (robot.device.maps)
|
|
||||||
{
|
{
|
||||||
robot.device.maps.forEach((map) =>
|
map.boundaries.forEach((boundary) =>
|
||||||
{
|
{
|
||||||
if (map.boundaries)
|
if (boundary.type === "polygon")
|
||||||
{
|
{
|
||||||
map.boundaries.forEach((boundary) =>
|
accessories.push(new NeatoVacuumRobotAccessory(robot, platform, boundary))
|
||||||
{
|
|
||||||
if (boundary.type === "polygon")
|
|
||||||
{
|
|
||||||
robot.boundary = boundary;
|
|
||||||
let roomAccessory = new KoboldVacuumRobotAccessory(this, robot);
|
|
||||||
accessories.push(roomAccessory);
|
|
||||||
|
|
||||||
robot.roomAccessories.push(roomAccessory);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
callback(accessories);
|
}
|
||||||
|
})
|
||||||
// // MOCK MULTIPLE ROBOTS START
|
}
|
||||||
// });
|
callback(accessories);
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// // MOCK MULTIPLE ROBOTS END
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getRobots: function (callback)
|
getRobots: function (callback)
|
||||||
{
|
{
|
||||||
debug("Loading your robots");
|
debug("Loading your robots");
|
||||||
let client = new control.Client();
|
let client = new botvac.Client();
|
||||||
|
let that = this;
|
||||||
// Login
|
client.authorize(this.email, this.password, false, (error) =>
|
||||||
client.authorize(this.token, (error) =>
|
|
||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
this.log.error("Can't log on to Vorwerk cloud. Please check your internet connection and your token. Try again later if the Vorwerk servers have issues: " + error);
|
that.log(error);
|
||||||
|
that.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.");
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get all robots
|
|
||||||
client.getRobots((error, robots) =>
|
client.getRobots((error, robots) =>
|
||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
this.log.error("Successful login but can't connect to your Vorwerk robot: " + error);
|
that.log(error);
|
||||||
callback();
|
that.log.error("Successful login but can't connect to your neato robot.");
|
||||||
}
|
|
||||||
else if (robots.length === 0)
|
|
||||||
{
|
|
||||||
this.log.error("Successful login but no robots associated with your account.");
|
|
||||||
this.robots = [];
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug("Found " + robots.length + " robots");
|
if (robots.length === 0)
|
||||||
let loadedRobots = 0;
|
|
||||||
|
|
||||||
robots.forEach((robot) =>
|
|
||||||
{
|
{
|
||||||
// Get additional information for the robot
|
that.log.error("Successful login but no robots associated with your account.");
|
||||||
robot.getState((error, state) =>
|
that.robots = [];
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug("Found " + robots.length + " robots");
|
||||||
|
let updatedRobotCount = 0;
|
||||||
|
that.robots = robots;
|
||||||
|
that.robots.forEach((robot) =>
|
||||||
{
|
{
|
||||||
if (error)
|
robot.getPersistentMaps((error, result) =>
|
||||||
{
|
{
|
||||||
this.log.error("Error getting robot meta information: " + error + ": " + state);
|
if (error)
|
||||||
callback();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get all maps for each robot
|
|
||||||
robot.getPersistentMaps((error, maps) =>
|
|
||||||
{
|
{
|
||||||
if (error)
|
that.log("Error updating persistent maps: " + error + ": " + result);
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
robot.maps = result;
|
||||||
|
let processedMapCount = 0;
|
||||||
|
if (robot.maps.length === 0)
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
robot.maps.forEach((map) =>
|
||||||
|
{
|
||||||
|
robot.getMapBoundaries(map.id, (error, result) =>
|
||||||
{
|
{
|
||||||
this.log.error("Error updating persistent maps: " + error + ": " + maps);
|
if (error)
|
||||||
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();
|
this.log("error getting boundaries: " + error + ": " + result)
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
// Robot has maps
|
|
||||||
else
|
|
||||||
{
|
|
||||||
robot.maps = maps;
|
|
||||||
let loadedMaps = 0;
|
|
||||||
robot.maps.forEach((map) =>
|
|
||||||
{
|
{
|
||||||
// Save zones in each map
|
map.boundaries = result.boundaries;
|
||||||
robot.getMapBoundaries(map.id, (error, result) =>
|
}
|
||||||
|
processedMapCount++;
|
||||||
|
if (processedMapCount === robot.maps.length)
|
||||||
|
{
|
||||||
|
updatedRobotCount++;
|
||||||
|
if (updatedRobotCount === that.robots.length)
|
||||||
{
|
{
|
||||||
if (error)
|
callback();
|
||||||
{
|
}
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
updateRobot: function (serial, callback)
|
|
||||||
{
|
|
||||||
let robot = this.getRobot(serial);
|
|
||||||
|
|
||||||
// Data is up to date
|
|
||||||
if (typeof (robot.lastUpdate) !== 'undefined' && new Date() - robot.lastUpdate < 2000)
|
|
||||||
{
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getRobot(serial)
|
|
||||||
{
|
|
||||||
let result;
|
|
||||||
this.robots.forEach(function (robot)
|
|
||||||
{
|
|
||||||
if (robot.device._serial === serial)
|
|
||||||
{
|
|
||||||
result = robot;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
// 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 refresh
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug(robot.device.name + ": ++ Stopped background updates");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
};
|
31
package.json
31
package.json
@ -1,35 +1,42 @@
|
|||||||
{
|
{
|
||||||
"name": "homebridge-kobold",
|
"name": "homebridge-neato",
|
||||||
"version": "0.8.4",
|
"version": "0.7.0-beta.0",
|
||||||
"description": "A Vorwerk Kobold vacuum robot plugin for homebridge.",
|
"description": "A Neato vacuum robot plugin for homebridge.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"homebridge-plugin",
|
"homebridge-plugin",
|
||||||
"vorwerk",
|
"neato",
|
||||||
"kobold"
|
"botvac"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12.0",
|
"node": ">=0.12.0",
|
||||||
"homebridge": ">=0.2.0"
|
"homebridge": ">=0.2.0"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Luis R.",
|
"name": "Arne Blumentritt",
|
||||||
"url2": "https://github.com/himbeles"
|
"url2": "https://github.com/naofireblade"
|
||||||
},
|
},
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"name": "Alexandre L.",
|
"name": "ghulands",
|
||||||
"url": "https://github.com/aluini"
|
"url": "https://github.com/ghulands"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Berkay",
|
||||||
|
"url": "https://github.com/btutal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Antoine de Maleprade",
|
||||||
|
"url": "https://github.com/az0uz"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/himbeles/homebridge-kobold.git"
|
"url": "git://github.com/naofireblade/homebridge-neato.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colors": "^1.4.0",
|
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"node-kobold-control": ">=0.4.2",
|
"node-botvac": ">=0.3.0",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user