Improved handling of differences between robots in account and cache
Added debug output for all robots in account
This commit is contained in:
parent
e53bb3d777
commit
bc527a60ba
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "homebridge-neato",
|
"name": "homebridge-neato",
|
||||||
"displayName": "Homebridge Neato",
|
"displayName": "Homebridge Neato",
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.3",
|
||||||
"description": "A Neato vacuum robot plugin for homebridge.",
|
"description": "A Neato vacuum robot plugin for homebridge.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
45
src/api.ts
Normal file
45
src/api.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
var axios = require('axios');
|
||||||
|
|
||||||
|
function request(url, payload, method, headers, callback) {
|
||||||
|
if (!url || url === '') {
|
||||||
|
if (typeof callback === 'function') callback('no url specified');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
data: null,
|
||||||
|
method: method === 'GET' ? 'GET' : 'POST',
|
||||||
|
url: url,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/vnd.neato.nucleo.v1'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.method === 'POST') {
|
||||||
|
options.data = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof headers === 'object') {
|
||||||
|
for (var header in headers) {
|
||||||
|
if (headers.hasOwnProperty(header)) {
|
||||||
|
options.headers[header] = headers[header];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res, err;
|
||||||
|
|
||||||
|
axios(options)
|
||||||
|
.then(function (response) {
|
||||||
|
res = response.data;
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
err = error;
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
// Callback needs to be called in finally block, see: https://github.com/Pmant/node-botvac/issues/15
|
||||||
|
if (typeof callback === 'function') callback(err, res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.request = request;
|
@ -3,6 +3,8 @@ import NeatoApi from "node-botvac";
|
|||||||
import {PLATFORM_NAME, PLUGIN_NAME} from "./settings";
|
import {PLATFORM_NAME, PLUGIN_NAME} from "./settings";
|
||||||
import {NeatoVacuumRobotAccessory} from "./accessories/NeatoVacuumRobot";
|
import {NeatoVacuumRobotAccessory} from "./accessories/NeatoVacuumRobot";
|
||||||
|
|
||||||
|
const api = require("./api");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HomebridgePlatform
|
* HomebridgePlatform
|
||||||
* This class is the main constructor for your plugin, this is where you should
|
* This class is the main constructor for your plugin, this is where you should
|
||||||
@ -14,7 +16,7 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic;
|
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic;
|
||||||
|
|
||||||
// this is used to track restored cached accessories
|
// this is used to track restored cached accessories
|
||||||
public readonly robotAccessories: PlatformAccessory[] = [];
|
public readonly cachedRobotAccessories: PlatformAccessory[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly log: Logger,
|
public readonly log: Logger,
|
||||||
@ -33,12 +35,13 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
configureAccessory(accessory: PlatformAccessory)
|
configureAccessory(accessory: PlatformAccessory)
|
||||||
{
|
{
|
||||||
// add the restored accessory to the accessories cache so we can track if it has already been registered
|
// add the restored accessory to the accessories cache so we can track if it has already been registered
|
||||||
this.robotAccessories.push(accessory);
|
this.cachedRobotAccessories.push(accessory);
|
||||||
}
|
}
|
||||||
|
|
||||||
discoverRobots()
|
discoverRobots()
|
||||||
{
|
{
|
||||||
const client = new NeatoApi.Client();
|
const client = new NeatoApi.Client();
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -52,30 +55,77 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug robot request TODO: remove after beta
|
||||||
|
let that = this;
|
||||||
|
api.request(client._baseUrl + '/users/me/robots', null, 'GET', {Authorization: client._tokenType + client._token}, (function (error, result) {
|
||||||
|
result.forEach(r => {
|
||||||
|
r.serial = "xxx" + r.serial.length;
|
||||||
|
r.secret_key = "xxx" + r.secret_key.length;
|
||||||
|
r.mac_address = "xxx" + r.mac_address.length;
|
||||||
|
that.log.debug("Robot Request Result: " + JSON.stringify(r));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
that.log.debug("Robot Request Error: " + JSON.stringify(error));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// Get all robots from account
|
// Get all robots from account
|
||||||
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 list your neato robots. Error: " + error);
|
||||||
// TODO retry after x min
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (robots.length === 0)
|
|
||||||
{
|
|
||||||
this.log.error("Successful login but no robots associated with your account.");
|
|
||||||
// TODO retry after x min
|
// TODO retry after x min
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log.info("Neato account has " + robots.length + " robot " + (robots.length === 1 ? "" : "s"));
|
// Neato robots in account
|
||||||
|
if (robots.length === 0)
|
||||||
for (const robot of robots)
|
|
||||||
{
|
{
|
||||||
// Get additional information for the robot
|
this.log.error("Neato account has no robots. Did you add your robot here: https://neatorobotics.com/my-neato/ ?");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.log.info("Neato account has " + robots.length + " robot" + (robots.length === 1 ? "" : "s"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neato robots in cache
|
||||||
|
this.log.debug("Plugin Cache has " + this.cachedRobotAccessories.length + " robot" + (this.cachedRobotAccessories.length === 1 ? "" : "s"));
|
||||||
|
for (let cachedRobot of this.cachedRobotAccessories)
|
||||||
|
{
|
||||||
|
let accountRobot = robots.find(robot => this.api.hap.uuid.generate(robot._serial) === cachedRobot.UUID);
|
||||||
|
if (accountRobot)
|
||||||
|
{
|
||||||
|
this.log.debug("[" + cachedRobot.displayName + "] Cached robot found in Neato account.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.log.error("[" + cachedRobot.displayName + "] Cached robot not found in Neato account. Robot will now be removed from homebridge.");
|
||||||
|
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [cachedRobot]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add / Update homebridge accessories with robot information from neato. This must be done for new and existing robots to reflect changes in the name, firmware, pluginconfig etc.
|
||||||
|
for (let robot of robots)
|
||||||
|
{
|
||||||
|
// Check if robot already exists as an accessory
|
||||||
|
const uuid = this.api.hap.uuid.generate(robot._serial);
|
||||||
|
const cachedRobot = this.cachedRobotAccessories.find(accessory => accessory.UUID === uuid);
|
||||||
|
|
||||||
|
if (cachedRobot)
|
||||||
|
{
|
||||||
|
this.log.debug("[" + robot.name + "] Updating meta information for robot in cache.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.log.debug("[" + robot.name + "] Getting meta information for new robot.");
|
||||||
|
}
|
||||||
|
|
||||||
robot.getState((error, state) => {
|
robot.getState((error, state) => {
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
this.log.error("Error getting robot meta information: " + error + ": " + state);
|
this.log.error("[" + robot.name + "] Error getting meta information. Is the robot connected to the internet? Error: " + error + ". State: " + state);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -83,40 +133,33 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
{
|
{
|
||||||
robot.meta = state.meta;
|
robot.meta = state.meta;
|
||||||
|
|
||||||
const uuid = this.api.hap.uuid.generate(robot._serial);
|
// Update existing robot accessor
|
||||||
const existingAccessory = this.robotAccessories.find(accessory => accessory.UUID === uuid);
|
if (cachedRobot)
|
||||||
|
|
||||||
// the accessory already exists
|
|
||||||
if (existingAccessory)
|
|
||||||
{
|
{
|
||||||
this.log.info("[" + robot.name + "] Robot loaded from cache");
|
|
||||||
// TODO update maps
|
// TODO update maps
|
||||||
|
|
||||||
existingAccessory.context.robot = robot;
|
cachedRobot.context.robot = robot;
|
||||||
this.api.updatePlatformAccessories([existingAccessory]);
|
this.api.updatePlatformAccessories([cachedRobot]);
|
||||||
|
new NeatoVacuumRobotAccessory(this, cachedRobot, this.config);
|
||||||
new NeatoVacuumRobotAccessory(this, existingAccessory, this.config);
|
this.log.info("[" + robot.name + "] Successfully loaded from cache");
|
||||||
}
|
}
|
||||||
|
// Create new robot accessory
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.log.info("[" + robot.name + "] Robot created");
|
|
||||||
const accessory = new this.api.platformAccessory(robot.name, uuid);
|
|
||||||
|
|
||||||
accessory.context.robot = robot;
|
|
||||||
new NeatoVacuumRobotAccessory(this, accessory, this.config);
|
|
||||||
|
|
||||||
// link the accessory to your platform
|
|
||||||
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
||||||
// TODO get maps
|
// TODO get maps
|
||||||
|
|
||||||
|
const newRobot = new this.api.platformAccessory(robot.name, uuid);
|
||||||
|
newRobot.context.robot = robot;
|
||||||
|
new NeatoVacuumRobotAccessory(this, newRobot, this.config);
|
||||||
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [newRobot]);
|
||||||
|
this.log.info("[" + robot.name + "] Successfully created as new robot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
this.log.error("Error creating robot accessory: " + robot.name);
|
this.log.error("[" + robot.name + "] Creating accessory failed. Error: " + error);
|
||||||
this.log.error(error);
|
|
||||||
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
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
|
||||||
@ -176,7 +219,7 @@ export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
|
|||||||
}
|
}
|
||||||
catch (error)
|
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);
|
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: " + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user