homebridge-kobold-Homaassis.../src/homebridgeNeatoPlatform.ts
2021-04-29 19:46:31 +02:00

197 lines
6.8 KiB
TypeScript

import {API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service} from 'homebridge';
import Debug from "debug";
import NeatoApi from "node-botvac";
import {PLATFORM_NAME, PLUGIN_NAME} from './settings';
import {NeatoVacuumRobotAccessory} from './accessories/NeatoVacuumRobot';
const debug = Debug("homebridge-neato");
/**
* HomebridgePlatform
* This class is the main constructor for your plugin, this is where you should
* parse the user config and discover/register accessories with Homebridge.
*/
export class HomebridgeNeatoPlatform implements DynamicPlatformPlugin
{
public readonly Service: typeof Service = this.api.hap.Service;
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic;
// this is used to track restored cached accessories
public readonly robotAccessories: PlatformAccessory[] = [];
constructor(
public readonly log: Logger,
public readonly config: PlatformConfig,
public readonly api: API)
{
this.log.debug('Finished initializing platform:', this.config.name);
this.api.on('didFinishLaunching', () => {
log.debug('Executed didFinishLaunching callback');
this.discoverRobots();
});
}
/**
* This function is invoked when homebridge restores cached accessories from disk at startup.
* It should be used to setup event handlers for characteristics and update respective values.
*/
configureAccessory(accessory: PlatformAccessory)
{
this.log.info('Loading accessory from cache:', accessory.displayName);
// add the restored accessory to the accessories cache so we can track if it has already been registered
this.robotAccessories.push(accessory);
}
discoverRobots()
{
debug("Discovering new robots");
let client = new NeatoApi.Client();
try
{
// Login
client.authorize((this.config)['email'], (this.config)['password'], false, (error) => {
if (error)
{
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}
// Get all robots from account
client.getRobots((error, robots) => {
if (error)
{
this.log.error("Successful login but can't connect to your neato robot: " + error);
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}
else if (robots.length === 0)
{
this.log.error("Successful login but no robots associated with your account.");
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}
debug("Found " + robots.length + " robots");
let loadedRobots = 0;
for (let robot of robots)
{
// Get additional information for the robot
robot.getState((error, state) => {
this.log.debug("Got state for robot: " + robot.name);
robot.meta = state.meta;
if (error)
{
this.log.error("Error getting robot meta information: " + error + ": " + state);
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
}
try
{
const uuid = this.api.hap.uuid.generate(robot._serial);
const existingAccessory = this.robotAccessories.find(accessory => accessory.UUID === uuid);
if (existingAccessory)
{
// the accessory already exists
this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
existingAccessory.context.robot = robot;
// TODO update maps
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
// existingAccessory.context.device = device;
// this.api.updatePlatformAccessories([existingAccessory]);
// create the accessory handler for the restored accessory
// this is imported from `platformAccessory.ts`
new NeatoVacuumRobotAccessory(this, existingAccessory, false);
// it is possible to remove platform accessories at any time using `api.unregisterPlatformAccessories`, eg.:
// remove platform accessories when no longer present
// this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
// this.log.info('Removing existing accessory from cache:', existingAccessory.displayName);
}
else
{
this.log.info('Adding new accessory: ', robot.name);
const accessory = new this.api.platformAccessory(robot.name, uuid);
accessory.context.robot = robot;
new NeatoVacuumRobotAccessory(this, accessory, true);
// link the accessory to your platform
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
// 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
// robot.getPersistentMaps((error, maps) => {
// if (error)
// {
// this.log.error("Error updating persistent maps: " + error + ": " + maps);
// callback();
// }
// // Robot has no maps
// else if (maps.length === 0)
// {
// robot.maps = [];
// this.robotAccessories.push({device: robot, meta: state.meta, availableServices: state.availableServices});
// loadedRobots++;
// if (loadedRobots === robots.length)
// {
// callback();
// }
// }
// // Robot has maps
// else
// {
// robot.maps = maps;
// let loadedMaps = 0;
// robot.maps.forEach((map) => {
// // Save zones in each map
// robot.getMapBoundaries(map.id, (error, result) => {
// if (error)
// {
// this.log.error("Error getting boundaries: " + error + ": " + result)
// }
// else
// {
// map.boundaries = result.boundaries;
// }
// loadedMaps++;
//
// // Robot is completely requested if zones for all maps are loaded
// if (loadedMaps === robot.maps.length)
// {
// this.robotAccessories.push({device: robot, meta: state.meta, availableServices: state.availableServices});
// loadedRobots++;
// if (loadedRobots === robots.length)
// {
// callback();
// }
// }
// })
// });
// }
// });
});
}
});
});
}
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);
}
}
}