WIP dynamic platform
This commit is contained in:
parent
4a97891dfd
commit
0ed30314df
9
homebridge-neato.iml
Normal file
9
homebridge-neato.iml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
2841
package-lock.json
generated
Normal file
2841
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -48,7 +48,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
"node-botvac": "^0.4.0",
|
"node-botvac": "^0.4.1",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {CharacteristicValue, PlatformAccessory, Service} from 'homebridge';
|
import {CharacteristicValue, Logger, PlatformAccessory, Service} from 'homebridge';
|
||||||
import {HomebridgeNeatoPlatform} from '../homebridgeNeatoPlatform';
|
import {HomebridgeNeatoPlatform} from '../homebridgeNeatoPlatform';
|
||||||
|
|
||||||
const debug = require('debug')('my-app:my-module');
|
const debug = require('debug')('my-app:my-module');
|
||||||
@ -10,14 +10,15 @@ const debug = require('debug')('my-app:my-module');
|
|||||||
export class NeatoVacuumRobotAccessory
|
export class NeatoVacuumRobotAccessory
|
||||||
{
|
{
|
||||||
private cleanService: Service;
|
private cleanService: Service;
|
||||||
|
private findMeService: Service;
|
||||||
private robot: any;
|
private robot: any;
|
||||||
|
private log: Logger;
|
||||||
// private goToDockService: Service;
|
// private goToDockService: Service;
|
||||||
// private dockStateService: Service;
|
// private dockStateService: Service;
|
||||||
// private ecoService: Service;
|
// private ecoService: Service;
|
||||||
// private noGoLinesService: Service;
|
// private noGoLinesService: Service;
|
||||||
// private extraCareService: Service;
|
// private extraCareService: Service;
|
||||||
// private scheduleService: Service;
|
// private scheduleService: Service;
|
||||||
// private findMeService: Service;
|
|
||||||
// private spotCleanService: Service;
|
// private spotCleanService: Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,6 +32,7 @@ export class NeatoVacuumRobotAccessory
|
|||||||
private readonly isNew: Boolean)
|
private readonly isNew: Boolean)
|
||||||
{
|
{
|
||||||
this.robot = accessory.context.robot;
|
this.robot = accessory.context.robot;
|
||||||
|
this.log = platform.log;
|
||||||
|
|
||||||
// set accessory information
|
// set accessory information
|
||||||
this.accessory.getService(this.platform.Service.AccessoryInformation)!
|
this.accessory.getService(this.platform.Service.AccessoryInformation)!
|
||||||
@ -40,13 +42,17 @@ export class NeatoVacuumRobotAccessory
|
|||||||
.setCharacteristic(this.platform.Characteristic.FirmwareRevision, this.robot.meta.firmware)
|
.setCharacteristic(this.platform.Characteristic.FirmwareRevision, this.robot.meta.firmware)
|
||||||
.setCharacteristic(this.platform.Characteristic.Name, this.robot.name);
|
.setCharacteristic(this.platform.Characteristic.Name, this.robot.name);
|
||||||
|
|
||||||
|
let cleanServiceName = this.robot.name + " Clean";
|
||||||
let cleanServiceName = robot.name + " Clean";
|
|
||||||
this.cleanService = this.accessory.getService(cleanServiceName) || this.accessory.addService(this.platform.Service.Switch, cleanServiceName, "CLEAN");
|
this.cleanService = this.accessory.getService(cleanServiceName) || this.accessory.addService(this.platform.Service.Switch, cleanServiceName, "CLEAN");
|
||||||
|
let findMeServiceName = this.robot.name + " Find Me";
|
||||||
|
this.findMeService = this.accessory.getService(findMeServiceName) || this.accessory.addService(this.platform.Service.Switch, findMeServiceName, "FIND_ME");
|
||||||
|
|
||||||
this.cleanService.getCharacteristic(this.platform.Characteristic.On)
|
this.cleanService.getCharacteristic(this.platform.Characteristic.On)
|
||||||
.onSet(this.setClean.bind(this))
|
.onSet(this.setClean.bind(this))
|
||||||
.onGet(this.getClean.bind(this));
|
.onGet(this.getClean.bind(this));
|
||||||
|
this.findMeService.getCharacteristic(this.platform.Characteristic.On)
|
||||||
|
.onSet(this.setFindMe.bind(this))
|
||||||
|
.onGet(this.getFindMe.bind(this));
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Updating characteristics values asynchronously.
|
// * Updating characteristics values asynchronously.
|
||||||
@ -75,33 +81,33 @@ export class NeatoVacuumRobotAccessory
|
|||||||
async setClean(on: CharacteristicValue)
|
async setClean(on: CharacteristicValue)
|
||||||
{
|
{
|
||||||
// TODO debug(this.robot.name + ": " + (on ? "Enabled ".brightGreen : "Disabled".red) + " Clean " + (this.boundary ? JSON.stringify(this.boundary) : ''));
|
// TODO debug(this.robot.name + ": " + (on ? "Enabled ".brightGreen : "Disabled".red) + " Clean " + (this.boundary ? JSON.stringify(this.boundary) : ''));
|
||||||
this.platform.updateRobot(this.robot._serial, (error, result) =>
|
try
|
||||||
{
|
{
|
||||||
|
await this.updateRobot();
|
||||||
|
|
||||||
// Start
|
// Start
|
||||||
if (on)
|
if (on)
|
||||||
{
|
{
|
||||||
// No room given or same room
|
// No room given or same room
|
||||||
if (this.boundary == null || this.robot.cleaningBoundaryId === this.boundary.id)
|
if (this.robot.boundary == null || this.robot.cleaningBoundaryId === this.robot.boundary.id)
|
||||||
{
|
{
|
||||||
// Resume cleaning
|
// Resume cleaning
|
||||||
if (this.robot.canResume)
|
if (this.robot.canResume)
|
||||||
{
|
{
|
||||||
debug(this.name + ": ## Resume cleaning");
|
debug(this.robot.name + ": ## Resume cleaning");
|
||||||
this.robot.resumeCleaning((error) =>
|
await this.robot.resumeCleaning();
|
||||||
{
|
return;
|
||||||
callback(error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// Start cleaning
|
// Start cleaning
|
||||||
else if (this.robot.canStart)
|
else if (this.robot.canStart)
|
||||||
{
|
{
|
||||||
this.clean(callback);
|
// TODO this.clean(callback);
|
||||||
}
|
}
|
||||||
// Cannot start
|
// Cannot start
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug(this.name + ": Cannot start, maybe already cleaning (expected)");
|
// TODO debug(this.name + ": Cannot start, maybe already cleaning (expected)");
|
||||||
callback();
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Different room given
|
// Different room given
|
||||||
@ -110,18 +116,18 @@ export class NeatoVacuumRobotAccessory
|
|||||||
// Return to dock
|
// Return to dock
|
||||||
if (this.robot.canPause || this.robot.canResume)
|
if (this.robot.canPause || this.robot.canResume)
|
||||||
{
|
{
|
||||||
debug(this.name + ": ## Returning to dock to start cleaning of new room");
|
// debug(this.name + ": ## Returning to dock to start cleaning of new room");
|
||||||
this.setGoToDock(true, (error, result) =>
|
// this.setGoToDock(true, (error, result) =>
|
||||||
{
|
// {
|
||||||
this.nextRoom = this.boundary.id;
|
// this.nextRoom = this.boundary.id;
|
||||||
callback();
|
// callback();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
// Start new cleaning of new room
|
// Start new cleaning of new room
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug(this.name + ": ## Start cleaning of new room");
|
// debug(this.name + ": ## Start cleaning of new room");
|
||||||
this.clean(callback);
|
// this.clean(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,32 +136,99 @@ export class NeatoVacuumRobotAccessory
|
|||||||
{
|
{
|
||||||
if (this.robot.canPause)
|
if (this.robot.canPause)
|
||||||
{
|
{
|
||||||
debug(this.name + ": ## Pause cleaning");
|
// debug(this.name + ": ## Pause cleaning");
|
||||||
this.robot.pauseCleaning((error) =>
|
// this.robot.pauseCleaning((error) => {
|
||||||
{
|
// callback(error);
|
||||||
callback(error);
|
// });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug(this.name + ": Already paused");
|
// debug(this.name + ": Already paused");
|
||||||
callback();
|
// callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
this.log.warn("Cannot start cleaning: " + error);
|
||||||
|
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getClean(): Promise<CharacteristicValue>
|
async getClean(): Promise<CharacteristicValue>
|
||||||
{
|
{
|
||||||
// implement your own code to check if the device is on
|
try
|
||||||
const isOn = this.exampleStates.On;
|
{
|
||||||
|
await this.updateRobot();
|
||||||
|
|
||||||
this.platform.log.debug('Get Characteristic On ->', isOn);
|
let cleaning;
|
||||||
|
if (this.robot.boundary == null)
|
||||||
|
{
|
||||||
|
cleaning = this.robot.canPause;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cleaning = this.robot.canPause && (this.robot.cleaningBoundaryId === this.robot.boundary.id)
|
||||||
|
}
|
||||||
|
|
||||||
// if you need to return an error to show the device as "Not Responding" in the Home app:
|
// TODO debug(this.robot.name + ": Cleaning is " + (cleaning ? 'ON'.brightGreen : 'OFF'.red));
|
||||||
// throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
return cleaning;
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
this.log.warn("Cannot get cleaning status: " + error);
|
||||||
|
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return isOn;
|
|
||||||
|
getFindMe()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setFindMe(on: CharacteristicValue)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
// TODO debug(this.name + ": ## Find me");
|
||||||
|
setTimeout(() => {
|
||||||
|
this.findMeService.updateCharacteristic(this.platform.Characteristic.On, false);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.robot.findMe();
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
this.log.warn("Cannot start find me: " + error);
|
||||||
|
throw new this.platform.api.hap.HapStatusError(this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateRobot()
|
||||||
|
{
|
||||||
|
// Data is up to date
|
||||||
|
if (typeof (this.robot.lastUpdate) !== 'undefined' && new Date().getTime() - this.robot.lastUpdate < 2000)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug(this.robot.name + ": ++ Updating robot state");
|
||||||
|
this.robot.lastUpdate = new Date().getTime();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.robot.getState();
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
this.log.error("Cannot update robot " + this.robot.name + ". Check if robot is online. " + error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,41 +49,45 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
debug("Discovering new robots");
|
debug("Discovering new robots");
|
||||||
let client = new NeatoApi.Client();
|
let client = new NeatoApi.Client();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
// Login
|
// Login
|
||||||
client.authorize((this.config)['email'], (this.config)['password'], false, (error) => {
|
client.authorize((this.config)['email'], (this.config)['password'], false, (error) => {
|
||||||
if (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);
|
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// Get all robots from account
|
||||||
// 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 neato robot: " + error);
|
this.log.error("Successful login but can't connect to your neato robot: " + error);
|
||||||
return;
|
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
}
|
}
|
||||||
else if (robots.length === 0)
|
else if (robots.length === 0)
|
||||||
{
|
{
|
||||||
this.log.error("Successful login but no robots associated with your account.");
|
this.log.error("Successful login but no robots associated with your account.");
|
||||||
return;
|
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
debug("Found " + robots.length + " robots");
|
debug("Found " + robots.length + " robots");
|
||||||
let loadedRobots = 0;
|
let loadedRobots = 0;
|
||||||
|
|
||||||
robots.forEach((robot) => {
|
for (let robot of robots)
|
||||||
|
{
|
||||||
// Get additional information for the robot
|
// Get additional information for the robot
|
||||||
robot.getState((error, state) => {
|
robot.getState((error, state) => {
|
||||||
|
this.log.debug("Got state for robot: " + robot.name);
|
||||||
|
robot.meta = state.meta;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
this.log.error("Error getting robot meta information: " + error + ": " + state);
|
this.log.error("Error getting robot meta information: " + error + ": " + state);
|
||||||
return;
|
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
const uuid = this.api.hap.uuid.generate(robot._serial);
|
const uuid = this.api.hap.uuid.generate(robot._serial);
|
||||||
const existingAccessory = this.robotAccessories.find(accessory => accessory.UUID === uuid);
|
const existingAccessory = this.robotAccessories.find(accessory => accessory.UUID === uuid);
|
||||||
@ -92,7 +96,7 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
{
|
{
|
||||||
// the accessory already exists
|
// the accessory already exists
|
||||||
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
|
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
|
||||||
|
existingAccessory.context.robot = robot;
|
||||||
// TODO update maps
|
// TODO update maps
|
||||||
|
|
||||||
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
||||||
@ -120,6 +124,13 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
||||||
// TODO get maps
|
// TODO get maps
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (error)
|
||||||
|
{
|
||||||
|
this.log.error("Error creating robot accessory: " + robot.name);
|
||||||
|
this.log.error(error);
|
||||||
|
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// // Get all maps for each robot
|
// // Get all maps for each robot
|
||||||
@ -172,12 +183,14 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
catch (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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { API } from 'homebridge';
|
import { API } from 'homebridge';
|
||||||
|
|
||||||
import { PLATFORM_NAME } from './settings';
|
import { PLATFORM_NAME } from './settings';
|
||||||
import { HomebridgeNeatoPlatform } from './platform';
|
import { HomebridgeNeatoPlatform } from './homebridgeNeatoPlatform';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method registers the platform with Homebridge
|
* This method registers the platform with Homebridge
|
||||||
|
Loading…
Reference in New Issue
Block a user