diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e6ff4bf --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +## 0.1.0 + +* Added start and pause cleaning +* Added return to base +* Added enable and disable schedule +* Added enable and disable eco mode +* Added battery info \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9941274 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Arne Blumentritt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b16511 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# homebridge-neato + +This is a plugin to control your [Neato](https://www.neatorobotics.com/) vacuum robot. + +# Installation + +1. Install homebridge using: npm install -g homebridge +2. Install this plugin using: npm install -g homebridge-neato +3. Update your configuration file. See the sample below. + +# Configuration + +Configuration sample: + +Add the following information to your config file. Change the values for name, email and password. + +```json +"accessories": [ + { + "accessory": "NeatoVacuumRobot", + "name": "YourRobot", + "email": "YourEmail", + "password": "YourPassword" + } + ] +``` + +# Features + +- Atart and pause cleaning +- Return to base +- Enable and disable schedule +- Enable and disable eco mode +- Get battery info + +# Tested robots + +- BotVac Connected Firmware 2.2.0 + +if you have another connected neato robot, please [tell me](https://github.com/naofireblade/homebridge-neato/issues/new) your experience with this plugin. \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..58d20d3 --- /dev/null +++ b/index.js @@ -0,0 +1,223 @@ +"use strict"; +var inherits = require('util').inherits; +var botvac = require('node-botvac'); + +var Service, Characteristic; + +module.exports = function (homebridge) { + Service = homebridge.hap.Service; + Characteristic = homebridge.hap.Characteristic; + homebridge.registerAccessory("homebridge-neato", "NeatoVacuumRobot", NeatoVacuumRobot); +} + +function NeatoVacuumRobot(log, config) { + this.log = log; + this.name = config['name']; + this.serial = "1-3-3-7"; + this.email = config['email']; + this.password = config['password']; + + this.lastUpdate = null; + this.robot = null; +} + +NeatoVacuumRobot.prototype = { + identify: function (callback) { + this.log("Identify requested"); + callback(); + }, + + getServices: function () { + this.informationService = new Service.AccessoryInformation(); + this.informationService + .setCharacteristic(Characteristic.Manufacturer, "Neato Robotics") + .setCharacteristic(Characteristic.Model, this.name) + .setCharacteristic(Characteristic.SerialNumber, this.serial); + + this.vacuumRobotCleanService = new Service.Switch(this.name + " Clean", "clean"); + this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('set', this.clean.bind(this)); + this.vacuumRobotCleanService.getCharacteristic(Characteristic.On).on('get', this.getClean.bind(this)); + + this.vacuumRobotDockService = new Service.Switch(this.name + " Dock", "dock"); + this.vacuumRobotDockService.getCharacteristic(Characteristic.On).on('set', this.dock.bind(this)); + this.vacuumRobotDockService.getCharacteristic(Characteristic.On).on('get', this.getDock.bind(this)); + + this.vacuumRobotEcoService = new Service.Switch(this.name + " Eco Mode", "eco"); + this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('set', this.eco.bind(this)); + this.vacuumRobotEcoService.getCharacteristic(Characteristic.On).on('get', this.getEco.bind(this)); + + this.vacuumRobotScheduleService = new Service.Switch(this.name + " Schedule", "schedule"); + this.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).on('set', this.schedule.bind(this)); + this.vacuumRobotScheduleService.getCharacteristic(Characteristic.On).on('get', this.getSchedule.bind(this)); + + this.vacuumRobotBatteryService = new Service.BatteryService("Battery", "battery"); + this.vacuumRobotBatteryService.getCharacteristic(Characteristic.BatteryLevel).on('get', this.getBatteryLevel.bind(this)); + this.vacuumRobotBatteryService.getCharacteristic(Characteristic.ChargingState).on('get', this.getBatteryChargingState.bind(this)); + + return [this.informationService, this.vacuumRobotCleanService, this.vacuumRobotDockService, this.vacuumRobotEcoService, + this.vacuumRobotScheduleService, this.vacuumRobotBatteryService]; + }, + + clean: function (on, callback) { + let that = this; + if (on) { + this.getState(function (error, result) { + that.log(that.robot); + if (that.robot.canResume === true) { + that.log("Resume cleaning"); + that.robot.resumeCleaning(function (error, result) { + that.log(result); + }); + } + else { + that.log("Start cleaning"); + that.robot.startCleaning(that.robot.eco, function (error, result) { + that.log(result); + }); + } + }); + } + else { + this.log("Pause cleaning"); + this.robot.pauseCleaning(false, function (error, result) { + that.log(result); + }); + } + callback(); + }, + + dock: function (on, callback) { + let that = this; + that.log(that.robot); + if (on) { + that.log("Send to dock"); + that.robot.sendToBase(false, function (error, result) { + that.log(result); + }); + } + callback(); + }, + + eco: function (on, callback) { + this.log(on ? "Enable eco mode" : "Disable eco mode"); + this.robot.eco = on; + callback(); + }, + + schedule: function (on, callback) { + if (on) { + this.log("Enable schedule"); + this.robot.enableSchedule(false, function (error, result) { + onsole.log(result); + }); + } + else { + this.log("Disable schedule"); + this.robot.disableSchedule(false, function (error, result) { + onsole.log(result); + }); + } + callback(); + }, + + getClean: function(callback) { + let that = this; + this.getState(function (error, result) { + that.log("Is cleaning: " + that.robot.canPause); + callback(false, that.robot.canPause); + }); + }, + + getDock: function(callback) { + let that = this; + this.getState(function (error, result) { + that.log("Can go to dock: " + that.robot.canGoToBase); + that.log("Is docked: " + that.robot.isDocked); + callback(false, that.robot.isDocked); + }); + }, + + getEco: function(callback) { + let that = this; + this.getState(function (error, result) { + that.log("Eco mode: " + that.robot.eco); + callback(false, that.robot.eco); + }); + }, + + getSchedule: function(callback) { + let that = this; + this.getState(function (error, result) { + that.log("Schedule: " + that.robot.isScheduleEnabled); + callback(false, that.robot.isScheduleEnabled); + }); + }, + + + getBatteryLevel: function(callback) { + let that = this; + this.getState(function (error, result) { + that.log("Battery: " + that.robot.charge); + callback(false, that.robot.charge); + }); + }, + + getBatteryChargingState: function(callback) { + let that = this; + this.getState(function (error, result) { + that.log("Is charging: " + that.robot.isCharging); + callback(false, that.robot.isCharging); + }); + }, + + getState: function(callback) { + let that = this; + if (this.robot === null) + { + this.getRobot(function (error, result) { + that._getState(callback); + }); + } + else { + that._getState(callback); + } + }, + + _getState: function(callback) { + if (this.lastUpdate !== null && new Date() - this.lastUpdate < 2000) { + //this.log("Get state (cached)"); + callback(); + } + else { + //this.log("Get state (new)"); + let that = this; + this.robot.getState(function (error, result) { + that.lastUpdate = new Date(); + callback(); + }); + } + }, + + getRobot: function(callback) { + //this.log("Get robot"); + let client = new botvac.Client(); + let that = this; + client.authorize(this.email, this.password, false, function (error) { + if (error) { + that.log(error); + } + else { + client.getRobots(function (error, robots) { + if (error) { + that.log(error); + } + else { + that.robot = robots[0]; + that.log("Found robot: " + that.robot.name); + callback(); + } + }); + } + }); + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..b210515 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "homebridge-neato", + "version": "0.1.0", + "description": "control your neato vacuum robot", + "license": "MIT", + "keywords": [ + "homebridge-plugin" + ], + "engines": { + "node": ">=0.12.0", + "homebridge": ">=0.2.0" + }, + "author": { + "name": "Arne Blumentritt" + }, + "repository": { + "type": "git", + "url": "git://github.com/naofireblade/homebridge-neato.git" + }, + "dependencies": { + "node-botvac": ">=0.1.4" + } +}