eslint compliance

This commit is contained in:
Luis Riegger 2021-05-10 20:51:29 +02:00
parent 9a9789328f
commit 82808d7850
8 changed files with 334 additions and 277 deletions

View File

@ -1,19 +1,21 @@
import type { Characteristic, WithUUID } from 'homebridge'; import type { Characteristic, WithUUID } from 'homebridge';
import { Formats, Perms } from 'homebridge'; import { Formats, Perms } from 'homebridge';
export default function spotHeight(CustomCharacteristic: typeof Characteristic): WithUUID<new () => Characteristic> { export default function spotHeight(
return class SpotHeight extends CustomCharacteristic { CustomCharacteristic: typeof Characteristic,
static readonly UUID = 'CA282DB2-62BF-4325-A1BE-F8BB5478781A'; ): WithUUID<new () => Characteristic> {
return class SpotHeight extends CustomCharacteristic {
static readonly UUID = 'CA282DB2-62BF-4325-A1BE-F8BB5478781A';
constructor() { constructor() {
super('Spot ↕', SpotHeight.UUID, { super('Spot ↕', SpotHeight.UUID, {
format: Formats.INT, format: Formats.INT,
unit: 'cm', unit: 'cm',
maxValue: 400, maxValue: 400,
minValue: 100, minValue: 100,
minStep: 50, minStep: 50,
perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE] perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE],
}); });
} }
}; };
} }

View File

@ -1,15 +1,17 @@
import type { Characteristic, WithUUID } from 'homebridge'; import type { Characteristic, WithUUID } from 'homebridge';
import { Formats, Perms } from 'homebridge'; import { Formats, Perms } from 'homebridge';
export default function spotRepeat(CustomCharacteristic: typeof Characteristic): WithUUID<new () => Characteristic> { export default function spotRepeat(
return class SpotRepeat extends CustomCharacteristic { CustomCharacteristic: typeof Characteristic,
static readonly UUID = '1E79C603-63B8-4E6A-9CE1-D31D67981831'; ): WithUUID<new () => Characteristic> {
return class SpotRepeat extends CustomCharacteristic {
static readonly UUID = '1E79C603-63B8-4E6A-9CE1-D31D67981831';
constructor() { constructor() {
super('Spot 2x', SpotRepeat.UUID, { super('Spot 2x', SpotRepeat.UUID, {
format: Formats.BOOL, format: Formats.BOOL,
perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE] perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE],
}); });
} }
}; };
} }

View File

@ -1,19 +1,21 @@
import type { Characteristic, WithUUID } from 'homebridge'; import type { Characteristic, WithUUID } from 'homebridge';
import { Formats, Perms } from 'homebridge'; import { Formats, Perms } from 'homebridge';
export default function spotWidth(CustomCharacteristic: typeof Characteristic): WithUUID<new () => Characteristic> { export default function spotWidth(
return class SpotWidth extends CustomCharacteristic { CustomCharacteristic: typeof Characteristic,
static readonly UUID = 'A7889A9A-2F27-4293-BEF8-3FE805B36F4E'; ): WithUUID<new () => Characteristic> {
return class SpotWidth extends CustomCharacteristic {
static readonly UUID = 'A7889A9A-2F27-4293-BEF8-3FE805B36F4E';
constructor() { constructor() {
super('Spot ↔', SpotWidth.UUID, { super('Spot ↔', SpotWidth.UUID, {
format: Formats.INT, format: Formats.INT,
unit: 'cm', unit: 'cm',
maxValue: 400, maxValue: 400,
minValue: 100, minValue: 100,
minStep: 50, minStep: 50,
perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE] perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE],
}); });
} }
}; };
} }

View File

@ -1,6 +1,6 @@
import { RobotService } from "./models/services"; import { RobotService } from './models/services';
export const BACKGROUND_INTERVAL = 30; export const BACKGROUND_INTERVAL = 30;
export const PREFIX = false; export const PREFIX = false;
export const ALL_SERVICES = new Set(Object.values(RobotService)); export const ALL_SERVICES = new Set(Object.values(RobotService));
export const LOCALE = "en" export const LOCALE = 'en';

View File

@ -1,219 +1,273 @@
import {API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service} from "homebridge"; import {
import KoboldApi from "node-kobold-control"; API,
import {PLATFORM_NAME, PLUGIN_NAME} from "./settings"; Characteristic,
import {KoboldVacuumRobotAccessory} from "./accessories/koboldVacuumRobot"; DynamicPlatformPlugin,
Logger,
PlatformAccessory,
PlatformConfig,
Service,
} from 'homebridge';
import KoboldApi from 'node-kobold-control';
import { PLATFORM_NAME, PLUGIN_NAME } from './settings';
import { KoboldVacuumRobotAccessory } from './accessories/koboldVacuumRobot';
/** /**
* 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
* parse the user config and discover/register accessories with Homebridge. * parse the user config and discover/register accessories with Homebridge.
*/ */
export class HomebridgeKoboldPlatform implements DynamicPlatformPlugin export class HomebridgeKoboldPlatform implements DynamicPlatformPlugin {
{ public readonly Service: typeof Service = this.api.hap.Service;
public readonly Service: typeof Service = this.api.hap.Service; public readonly Characteristic: typeof Characteristic =
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic; this.api.hap.Characteristic;
// this is used to track restored cached accessories // this is used to track restored cached accessories
public readonly cachedRobotAccessories: PlatformAccessory[] = []; public readonly cachedRobotAccessories: PlatformAccessory[] = [];
constructor( constructor(
public readonly log: Logger, public readonly log: Logger,
public readonly config: PlatformConfig, public readonly config: PlatformConfig,
public readonly api: API) public readonly api: API,
{ ) {
this.api.on("didFinishLaunching", () => { this.api.on('didFinishLaunching', () => {
this.discoverRobots(); this.discoverRobots();
}); });
} }
/** /**
* This function is invoked when homebridge restores cached accessories from disk at startup. * 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. * It should be used to setup event handlers for characteristics and update respective values.
*/ */
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.cachedRobotAccessories.push(accessory);
this.cachedRobotAccessories.push(accessory); }
}
discoverRobots() {
const client = new KoboldApi.Client();
discoverRobots() try {
{ // Login
const client = new KoboldApi.Client(); client.authorize(this.config['token'], (error) => {
if (error) {
this.log.error(
`Cannot connect to Vorwerk server.
No new robots will be found and existing robots will be unresponsive.
Retrying in 5 minutes.`,
);
this.log.error('Error: ' + error);
try setTimeout(() => {
{ this.discoverRobots();
// Login }, 5 * 60 * 1000);
client.authorize((this.config)["token"], (error) => { return;
if (error) }
{
this.log.error("Cannot connect to Vorwerk server. No new robots will be found and existing robots will be unresponsive. Retrying in 5 minutes.");
this.log.error("Error: " + error);
setTimeout(() => { // Get all robots from account
this.discoverRobots(); client.getRobots((error, robots) => {
}, 5 * 60 * 1000); if (error) {
return; this.log.error(
} 'Successful login but can\'t list the robots in your Vorwerk robots. Retrying in 5 minutes.',
);
this.log.error('Error: ' + error);
// Get all robots from account setTimeout(() => {
client.getRobots((error, robots) => { this.discoverRobots();
if (error) }, 5 * 60 * 1000);
{ return;
this.log.error("Successful login but can't list the robots in your Vorwerk robots. Retrying in 5 minutes."); }
this.log.error("Error: " + error);
setTimeout(() => { // Vorwerk robots in account
this.discoverRobots(); if (robots.length === 0) {
}, 5 * 60 * 1000); this.log.error('Vorwerk account has no robots.');
return; } else {
} this.log.info(
'Vorwerk account has ' +
robots.length +
' robot' +
(robots.length === 1 ? '' : 's'),
);
}
// Vorwerk robots in account // Vorwerk robots in cache
if (robots.length === 0) this.log.debug(
{ 'Plugin Cache has ' +
this.log.error("Vorwerk account has no robots."); this.cachedRobotAccessories.length +
} ' robot' +
else (this.cachedRobotAccessories.length === 1 ? '' : 's'),
{ );
this.log.info("Vorwerk account has " + robots.length + " robot" + (robots.length === 1 ? "" : "s")); for (const cachedRobot of this.cachedRobotAccessories) {
} const accountRobot = robots.find(
(robot) =>
this.api.hap.uuid.generate(robot._serial) === cachedRobot.UUID,
);
if (accountRobot) {
this.log.debug(
'[' +
cachedRobot.displayName +
'] Cached robot found in Vorwerk account.',
);
} else {
this.log.error(
'[' +
cachedRobot.displayName +
'] Cached robot not found in Vorwerk account. Robot will now be removed from homebridge.',
);
this.api.unregisterPlatformAccessories(
PLUGIN_NAME,
PLATFORM_NAME,
[cachedRobot],
);
}
}
// Vorwerk robots in cache // Add / Update homebridge accessories with robot information from Vorwerk.
this.log.debug("Plugin Cache has " + this.cachedRobotAccessories.length + " robot" + (this.cachedRobotAccessories.length === 1 ? "" : "s")); // This must be done for new and existing robots to reflect changes in the name, firmware, pluginconfig etc.
for (let cachedRobot of this.cachedRobotAccessories) for (const robot of robots) {
{ // Check if robot already exists as an accessory
let accountRobot = robots.find(robot => this.api.hap.uuid.generate(robot._serial) === cachedRobot.UUID); const uuid = this.api.hap.uuid.generate(robot._serial);
if (accountRobot) const cachedRobot = this.cachedRobotAccessories.find(
{ (accessory) => accessory.UUID === uuid,
this.log.debug("[" + cachedRobot.displayName + "] Cached robot found in Vorwerk account."); );
}
else
{
this.log.error("[" + cachedRobot.displayName + "] Cached robot not found in Vorwerk account. Robot will now be removed from homebridge.");
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [cachedRobot]);
}
}
// Add / Update homebridge accessories with robot information from Vorwerk. This must be done for new and existing robots to reflect changes in the name, firmware, pluginconfig etc. if (cachedRobot) {
for (let robot of robots) this.log.debug(
{ '[' +
// Check if robot already exists as an accessory robot.name +
const uuid = this.api.hap.uuid.generate(robot._serial); '] Connecting to cached robot and updating information.',
const cachedRobot = this.cachedRobotAccessories.find(accessory => accessory.UUID === uuid); );
} else {
this.log.debug(
'[' +
robot.name +
'] Connecting to new robot and updating information.',
);
}
if (cachedRobot) robot.getState((error, state) => {
{ if (error) {
this.log.debug("[" + robot.name + "] Connecting to cached robot and updating information."); this.log.error(
} '[' +
else robot.name +
{ '] Cannot connect to robot. Is the robot connected to the internet? Retrying in 5 minutes.',
this.log.debug("[" + robot.name + "] Connecting to new robot and updating information."); );
} this.log.error('Error: ' + error);
setTimeout(() => {
this.discoverRobots();
}, 5 * 60 * 1000);
} else {
try {
robot.meta = state.meta;
robot.availableServices = state.availableServices;
robot.getState((error, state) => { // Update existing robot accessor
if (error) if (cachedRobot) {
{ // TODO update maps
this.log.error("[" + robot.name + "] Cannot connect to robot. Is the robot connected to the internet? Retrying in 5 minutes.");
this.log.error("Error: " + error);
setTimeout(() => {
this.discoverRobots();
}, 5 * 60 * 1000);
}
else
{
try
{
robot.meta = state.meta;
robot.availableServices = state.availableServices;
// Update existing robot accessor cachedRobot.context.robot = robot;
if (cachedRobot) this.api.updatePlatformAccessories([cachedRobot]);
{ new KoboldVacuumRobotAccessory(
// TODO update maps this,
cachedRobot,
this.config,
);
this.log.info(
'[' +
robot.name +
'] Successfully loaded robot from cache',
);
} else {
// Create new robot accessory
// TODO get maps
cachedRobot.context.robot = robot; const newRobot = new this.api.platformAccessory(
this.api.updatePlatformAccessories([cachedRobot]); robot.name,
new KoboldVacuumRobotAccessory(this, cachedRobot, this.config); uuid,
this.log.info("[" + robot.name + "] Successfully loaded robot from cache"); );
} newRobot.context.robot = robot;
// Create new robot accessory new KoboldVacuumRobotAccessory(this, newRobot, this.config);
else this.api.registerPlatformAccessories(
{ PLUGIN_NAME,
// TODO get maps PLATFORM_NAME,
[newRobot],
);
this.log.info(
'[' + robot.name + '] Successfully created as new robot',
);
}
} catch (error) {
this.log.error(
'[' +
robot.name +
'] Creating accessory failed. Error: ' +
error,
);
throw new this.api.hap.HapStatusError(
this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
);
}
}
const newRobot = new this.api.platformAccessory(robot.name, uuid); // // Get all maps for each robot
newRobot.context.robot = robot; // robot.getPersistentMaps((error, maps) => {
new KoboldVacuumRobotAccessory(this, newRobot, this.config); // if (error)
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [newRobot]); // {
this.log.info("[" + robot.name + "] Successfully created as new robot"); // this.log.error("Error updating persistent maps: " + error + ": " + maps);
} // callback();
} // }
catch (error) // // Robot has no maps
{ // else if (maps.length === 0)
this.log.error("[" + robot.name + "] Creating accessory failed. Error: " + error); // {
throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE); // robot.maps = [];
} // this.robotAccessories.push({device: robot, meta: state.meta, availableServices: state.availableServices});
} // loadedRobots++;
// if (loadedRobots === robots.length)
// // Get all maps for each robot // {
// robot.getPersistentMaps((error, maps) => { // callback();
// if (error) // }
// { // }
// this.log.error("Error updating persistent maps: " + error + ": " + maps); // // Robot has maps
// callback(); // else
// } // {
// // Robot has no maps // robot.maps = maps;
// else if (maps.length === 0) // let loadedMaps = 0;
// { // robot.maps.forEach((map) => {
// robot.maps = []; // // Save zones in each map
// this.robotAccessories.push({device: robot, meta: state.meta, availableServices: state.availableServices}); // robot.getMapBoundaries(map.id, (error, result) => {
// loadedRobots++; // if (error)
// if (loadedRobots === robots.length) // {
// { // this.log.error("Error getting boundaries: " + error + ": " + result)
// callback(); // }
// } // else
// } // {
// // Robot has maps // map.boundaries = result.boundaries;
// else // }
// { // loadedMaps++;
// robot.maps = maps; //
// let loadedMaps = 0; // // Robot is completely requested if zones for all maps are loaded
// robot.maps.forEach((map) => { // if (loadedMaps === robot.maps.length)
// // Save zones in each map // {
// robot.getMapBoundaries(map.id, (error, result) => { // this.robotAccessories.push({device: robot, meta: state.meta, availableServices: state.availableServices});
// if (error) // loadedRobots++;
// { // if (loadedRobots === robots.length)
// this.log.error("Error getting boundaries: " + error + ": " + result) // {
// } // callback();
// 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++; } catch (error) {
// if (loadedRobots === robots.length) this.log.error(
// { `Can't log on to Vorwerk cloud. Please check your internet connection and your credentials.
// callback(); Try again later if the neato servers have issues. Error: ` +
// } error,
// } );
// }) }
// }); }
// }
// });
});
}
});
});
}
catch (error)
{
this.log.error("Can't log on to Vorwerk cloud. Please check your internet connection and your credentials. Try again later if the neato servers have issues. Error: " + error);
}
}
} }

View File

@ -1,12 +1,11 @@
import {API} from "homebridge"; import { API } from 'homebridge';
import {PLATFORM_NAME} from "./settings"; import { PLATFORM_NAME } from './settings';
import {HomebridgeKoboldPlatform} from "./homebridgeKoboldPlatform"; import { HomebridgeKoboldPlatform } from './homebridgeKoboldPlatform';
/** /**
* This method registers the platform with Homebridge * This method registers the platform with Homebridge
*/ */
export = (api: API) => export = (api: API) => {
{ api.registerPlatform(PLATFORM_NAME, HomebridgeKoboldPlatform);
api.registerPlatform(PLATFORM_NAME, HomebridgeKoboldPlatform);
}; };

View File

@ -1,21 +1,19 @@
export class Options export class Options {
{ public eco: boolean;
public eco: boolean; public extraCare: boolean;
public extraCare: boolean; public noGoLines: boolean;
public noGoLines: boolean; public spotCharacteristics: boolean;
public spotCharacteristics: boolean; public spotRepeat: boolean;
public spotRepeat: boolean; public spotWidth: number;
public spotWidth: number; public spotHeight: number;
public spotHeight: number;
constructor() constructor() {
{ this.eco = false;
this.eco = false; this.extraCare = false;
this.extraCare = false; this.noGoLines = false;
this.noGoLines = false; this.spotCharacteristics = false;
this.spotCharacteristics = false; this.spotRepeat = false;
this.spotRepeat = false; this.spotWidth = 200;
this.spotWidth = 200; this.spotHeight = 200;
this.spotHeight = 200; }
}
} }

View File

@ -4,16 +4,16 @@ export enum CleanType {
} }
export enum RobotService { export enum RobotService {
CLEAN = "clean", CLEAN = 'clean',
CLEAN_SPOT = "cleanSpot", CLEAN_SPOT = 'cleanSpot',
CLEAN_ZONE = "cleanZone", CLEAN_ZONE = 'cleanZone',
GO_TO_DOCK = "goToDock", GO_TO_DOCK = 'goToDock',
DOCKED = "dockState", DOCKED = 'dockState',
BIN_FULL = "binFull", BIN_FULL = 'binFull',
FIND_ME = "findMe", FIND_ME = 'findMe',
SCHEDULE = "schedule", SCHEDULE = 'schedule',
ECO = "eco", ECO = 'eco',
NOGO_LINES = "noGoLines", NOGO_LINES = 'noGoLines',
EXTRA_CARE = "extraCare", EXTRA_CARE = 'extraCare',
BATTERY = "battery", BATTERY = 'battery',
} }