From 423be484b261674e5372e58f0a410f8dec9754de Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sat, 7 Sep 2019 22:06:45 -0400 Subject: [PATCH] Fixed linting errors (Not tested) --- .eslintignore | 1 + .../HapClient/eventedHttpClient/httpParser.ts | 254 +++++++++--------- .../HapClient/eventedHttpClient/index.ts | 62 ++--- src/{3rdParty => }/HapClient/hap-types.ts | 2 +- src/{3rdParty => }/HapClient/hapClient.ts | 79 +++--- .../monitor.ts => HapClient/hapMonitor.ts} | 23 +- src/{3rdParty => }/HapClient/interfaces.ts | 0 src/Types/types.ts | 15 +- src/index.ts | 78 ++---- src/services/monitor.ts | 24 ++ 10 files changed, 279 insertions(+), 259 deletions(-) create mode 100644 .eslintignore rename src/{3rdParty => }/HapClient/eventedHttpClient/httpParser.ts (61%) rename src/{3rdParty => }/HapClient/eventedHttpClient/index.ts (82%) rename src/{3rdParty => }/HapClient/hap-types.ts (99%) rename src/{3rdParty => }/HapClient/hapClient.ts (90%) rename src/{3rdParty/HapClient/monitor.ts => HapClient/hapMonitor.ts} (86%) rename src/{3rdParty => }/HapClient/interfaces.ts (100%) create mode 100644 src/services/monitor.ts diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a9f3f5b --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/HAPNodeJS.d.ts diff --git a/src/3rdParty/HapClient/eventedHttpClient/httpParser.ts b/src/HapClient/eventedHttpClient/httpParser.ts similarity index 61% rename from src/3rdParty/HapClient/eventedHttpClient/httpParser.ts rename to src/HapClient/eventedHttpClient/httpParser.ts index 37e7f1a..8ed59ac 100755 --- a/src/3rdParty/HapClient/eventedHttpClient/httpParser.ts +++ b/src/HapClient/eventedHttpClient/httpParser.ts @@ -6,81 +6,84 @@ // Borrowed and heaviliy modifed from https://github.com/miguelmota/http-message-parser import { Buffer } from 'buffer'; -import { Dictionary } from '../../../Types/types'; +import { Dictionary } from '../../Types/types'; -interface httpResult { - protocol?: string, - httpVersion?: number, - statusCode?: number, - statusMessage?: string, - method?: string, - url?: string, - headers?: Dictionary, - body?: any, - boundary?: any, - multipart?: any, - additional?: any, - meta?: any +interface IHttpResult { + protocol?: string; + httpVersion?: number; + statusCode?: number; + statusMessage?: string; + method?: string; + url?: string; + headers?: Dictionary; + //eslint-disable-next-line + body?: any; + //eslint-disable-next-line + boundary?: any; + //eslint-disable-next-line + multipart?: any; + //eslint-disable-next-line + additional?: any; + //eslint-disable-next-line + meta?: any; } -function httpMessageParser(message: any) { - const result: httpResult = {} +export default class HttpMessageParser { + private static requestLineRegex = /(HTTP|EVENT)\/(1\.0|1\.1|2\.0)\s+(\d+)\s+([\w\s-_]+)/i; + private static responseLineRegex = /(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|TRACE|CONNECT)\s+(.*)\s+HTTP\/(1\.0|1\.1|2\.0)/i; + private static headerNewlineRegex = /^[\r\n]+/gim; + private static boundaryRegex = /(\n|\r\n)+--[\w-]+(\n|\r\n)+/g; - let messageString = ''; - let headerNewlineIndex = 0; - let fullBoundary: any = null; + //eslint-disable-next-line + public static parse(message: any): IHttpResult { + const result: IHttpResult = {}; - if (httpMessageParser._isBuffer(message)) { - messageString = message.toString(); - } else if (typeof message === 'string') { - messageString = message; - message = new Buffer(messageString); - } else { - return result; - } + let messageString = ''; + let headerNewlineIndex = 0; + //eslint-disable-next-line + let fullBoundary: any = null; - /* - * Strip extra return characters - */ - messageString = messageString.replace(/\r\n/gim, '\n'); - - /* - * Trim leading whitespace - */ - (function () { - const firstNonWhitespaceRegex = /[\w-]+/gim; - const firstNonWhitespaceIndex = messageString.search(firstNonWhitespaceRegex); - if (firstNonWhitespaceIndex > 0) { - message = message.slice(firstNonWhitespaceIndex, message.length); + if (this.isBuffer(message)) { messageString = message.toString(); + } else if (typeof message === 'string') { + messageString = message; + message = new Buffer(messageString); + } else { + return result; } - })(); - /* Parse request line - */ - (function () { + /* + * Strip extra return characters + */ + messageString = messageString.replace(/\r\n/gim, '\n'); + + messageString = this.trim(messageString); + + /* Parse request line + */ const possibleRequestLine = messageString.split(/\n|\r\n/)[0]; - const requestLineMatch = possibleRequestLine.match(httpMessageParser._requestLineRegex); + const requestLineMatch = possibleRequestLine.match(this.requestLineRegex); + /* Parse request line + */ if (Array.isArray(requestLineMatch) && requestLineMatch.length > 1) { result.protocol = requestLineMatch[1]; result.httpVersion = parseFloat(requestLineMatch[2]); result.statusCode = parseInt(requestLineMatch[3], 10); result.statusMessage = requestLineMatch[4]; } else { - const responseLineMath = possibleRequestLine.match(httpMessageParser._responseLineRegex); + const responseLineMath = possibleRequestLine.match(this.responseLineRegex); if (Array.isArray(responseLineMath) && responseLineMath.length > 1) { result.method = responseLineMath[1]; result.url = responseLineMath[2]; result.httpVersion = parseFloat(responseLineMath[3]); } } - })(); - /* Parse headers - */ - (function () { - headerNewlineIndex = messageString.search(httpMessageParser._headerNewlineRegex); + /* Parse headers + */ + + headerNewlineIndex = messageString.search(this.headerNewlineRegex); if (headerNewlineIndex > -1) { headerNewlineIndex = headerNewlineIndex + 1; // 1 for newline length } else { @@ -93,20 +96,18 @@ function httpMessageParser(message: any) { } const headersString = messageString.substr(0, headerNewlineIndex); - const headers = httpMessageParser._parseHeaders(headersString); + const headers = this.parseHeaders(headersString); if (Object.keys(headers).length > 0) { result.headers = headers; // TOOD: extract boundary. } - })(); - /* Try to get boundary if no boundary header - */ - (function () { + /* Try to get boundary if no boundary header + */ if (!result.boundary) { - const boundaryMatch = messageString.match(httpMessageParser._boundaryRegex); + const boundaryMatch = messageString.match(this.boundaryRegex); if (Array.isArray(boundaryMatch) && boundaryMatch.length) { fullBoundary = boundaryMatch[0].replace(/[\r\n]+/gi, ''); @@ -114,13 +115,11 @@ function httpMessageParser(message: any) { result.boundary = boundary; } } - })(); - /* Parse body - */ - (function () { + /* Parse body + */ let start = headerNewlineIndex; - let contentLength: number = result.headers!['Content-Length'] as number; + const contentLength: number = result.headers!['Content-Length'] as number; let end = (result.headers && result.headers['Content-Length'] && contentLength ? contentLength + start : messageString.length); @@ -154,11 +153,9 @@ function httpMessageParser(message: any) { } } } - })(); - /* Parse multipart sections - */ - (function () { + /* Parse multipart sections + */ if (result.boundary) { const multipartStart = messageString.indexOf(fullBoundary) + fullBoundary.length; const multipartEnd = messageString.lastIndexOf(fullBoundary); @@ -166,9 +163,9 @@ function httpMessageParser(message: any) { const splitRegex = new RegExp('^' + fullBoundary + '.*[\n\r]?$', 'gm'); const parts = multipartBody.split(splitRegex); - result.multipart = parts.filter(httpMessageParser._isTruthy).map(function (part, i) { + result.multipart = parts.filter(this.isTruthy).map(function (part, i) { // tslint:disable-next-line: no-shadowed-variable - const result: httpResult = {}; + const result: IHttpResult = {}; const newlineRegex = /\n\n|\r\n\r\n/gim; let newlineIndex = 0; @@ -191,7 +188,7 @@ function httpMessageParser(message: any) { let endOffset = null; if (newlineIndex > -1) { - const headers = httpMessageParser._parseHeaders(possibleHeadersString); + const headers = HttpMessageParser.parseHeaders(possibleHeadersString); if (Object.keys(headers).length > 0) { result.headers = headers; @@ -231,68 +228,73 @@ function httpMessageParser(message: any) { return result; }); } - })(); - return result; -} + return result; -httpMessageParser._isTruthy = function _isTruthy(value: any) { - return !!value; -}; - -httpMessageParser._isNumeric = function _isNumeric(value: any) { - if (typeof value === 'number' && !isNaN(value)) { - return true; } - value = (value || '').toString().trim(); - - if (!value) { - return false; - } - - return !isNaN(value); -}; - -httpMessageParser._isBuffer = function (item: any) { - return ((httpMessageParser._isNodeBufferSupported() && - typeof global === 'object' && - global.Buffer.isBuffer(item)) || - (item instanceof Object && - item._isBuffer)); -}; - -httpMessageParser._isNodeBufferSupported = function () { - return (typeof global === 'object' && - typeof global.Buffer === 'function' && - typeof global.Buffer.isBuffer === 'function'); -}; - -httpMessageParser._parseHeaders = function _parseHeaders(body: any) { - const headers: Dictionary = {}; - - if (typeof body !== 'string') { - return headers; - } - - body.split(/[\r\n]/).forEach(function (string) { - const match = string.match(/([\w-]+):\s*(.*)/i); - - if (Array.isArray(match) && match.length === 3) { - const key = match[1]; - const value = match[2]; - - headers[key] = httpMessageParser._isNumeric(value) ? Number(value) : value; + private static trim(str: string): string { + const firstNonWhitespaceRegex = /[\w-]+/gim; + const firstNonWhitespaceIndex = str.search(firstNonWhitespaceRegex); + let tmpStr = ""; + if (firstNonWhitespaceIndex > 0) { + tmpStr = str.slice(firstNonWhitespaceIndex, str.length); + str = tmpStr.toString(); } - }); - return headers; -}; + return str; + } -httpMessageParser._requestLineRegex = /(HTTP|EVENT)\/(1\.0|1\.1|2\.0)\s+(\d+)\s+([\w\s-_]+)/i; -httpMessageParser._responseLineRegex = /(GET|POST|PUT|DELETE|PATCH|OPTIONS|HEAD|TRACE|CONNECT)\s+(.*)\s+HTTP\/(1\.0|1\.1|2\.0)/i; -// httpMessageParser._headerNewlineRegex = /^[\r\n]+/gim; -httpMessageParser._headerNewlineRegex = /^[\r\n]+/gim; -httpMessageParser._boundaryRegex = /(\n|\r\n)+--[\w-]+(\n|\r\n)+/g; + private static isTruthy = function _isTruthy(value: any): boolean { + return !!value; + }; -export default httpMessageParser; + private static isNumeric = function _isNumeric(value: any): boolean { + if (typeof value === 'number' && !isNaN(value)) { + return true; + } + + value = (value || '').toString().trim(); + + if (!value) { + return false; + } + + return !isNaN(value); + }; + + private static isBuffer = (item: any): boolean => { + return ((HttpMessageParser.isNodeBufferSupported() && + typeof global === 'object' && + global.Buffer.isBuffer(item)) || + (item instanceof Object && + item._isBuffer)); + }; + + private static isNodeBufferSupported = (): boolean => { + return (typeof global === 'object' && + typeof global.Buffer === 'function' && + typeof global.Buffer.isBuffer === 'function'); + }; + + private static parseHeaders = (body: any): Dictionary => { + const headers: Dictionary = {}; + + if (typeof body !== 'string') { + return headers; + } + + body.split(/[\r\n]/).forEach(function (string) { + const match = string.match(/([\w-]+):\s*(.*)/i); + + if (Array.isArray(match) && match.length === 3) { + const key = match[1]; + const value = match[2]; + + headers[key] = HttpMessageParser.isNumeric(value) ? Number(value) : value; + } + }); + + return headers; + }; +} diff --git a/src/3rdParty/HapClient/eventedHttpClient/index.ts b/src/HapClient/eventedHttpClient/index.ts similarity index 82% rename from src/3rdParty/HapClient/eventedHttpClient/index.ts rename to src/HapClient/eventedHttpClient/index.ts index 75c2405..ea4058f 100755 --- a/src/3rdParty/HapClient/eventedHttpClient/index.ts +++ b/src/HapClient/eventedHttpClient/index.ts @@ -5,8 +5,8 @@ import * as net from 'net'; import * as url from 'url'; -import httpMessageParser from './/httpParser'; -import { Dictionary } from '../../../Types/types'; +import HttpMessageParser from './httpParser'; +import { Dictionary } from '../../Types/types'; interface IRequest { method: 'PUT' | 'POST' | 'GET' | 'DELETE' | 'PATCH'; @@ -16,7 +16,34 @@ interface IRequest { body: string; } -export const parseMessage = httpMessageParser; +export const parseMessage = HttpMessageParser.parse; + +function _headersToString(headers: Dictionary): string { + let response = ''; + + for (const header of Object.keys(headers)) { + response = response + header + ': ' + headers[header] + '\r\n'; + } + return (response); +} + +function _buildMessage(request: IRequest): string { + const context = url.parse(request.url); + let message; + + message = request.method + ' ' + context.pathname; + if (context.search) { + message = message + context.search; + } + message = message + ' HTTP/1.1\r\nHost: ' + context.host + '\r\n' + _headersToString(request.headers); + if (request.body) { + message = message + 'Content-Length: ' + request.body.length + '\r\n\r\n' + request.body + '\r\n\r\n'; + } else { + message = message + '\r\n\r\n'; + } + // debug("Message ->", message); + return (message); +} /** * Create a socket connection. @@ -24,7 +51,7 @@ export const parseMessage = httpMessageParser; * @param pin The authorization token * @param body The connection body */ -export function createConnection(instance: { ipAddress: string, port: number }, pin: string, body: any): net.Socket { +export function createConnection(instance: { ipAddress: string; port: number }, pin: string, body: unknown): net.Socket { const client: net.Socket = net.createConnection({ host: instance.ipAddress, port: instance.port, @@ -44,30 +71,3 @@ export function createConnection(instance: { ipAddress: string, port: number }, return client; } - -function _headersToString(headers: Dictionary) { - let response = ''; - - for (const header of Object.keys(headers)) { - response = response + header + ': ' + headers[header] + '\r\n'; - } - return (response); -} - -function _buildMessage(request: IRequest) { - const context = url.parse(request.url); - let message; - - message = request.method + ' ' + context.pathname; - if (context.search) { - message = message + context.search; - } - message = message + ' HTTP/1.1\r\nHost: ' + context.host + '\r\n' + _headersToString(request.headers); - if (request.body) { - message = message + 'Content-Length: ' + request.body.length + '\r\n\r\n' + request.body + '\r\n\r\n'; - } else { - message = message + '\r\n\r\n'; - } - // debug("Message ->", message); - return (message); -} diff --git a/src/3rdParty/HapClient/hap-types.ts b/src/HapClient/hap-types.ts similarity index 99% rename from src/3rdParty/HapClient/hap-types.ts rename to src/HapClient/hap-types.ts index 9f5b2e3..634c454 100755 --- a/src/3rdParty/HapClient/hap-types.ts +++ b/src/HapClient/hap-types.ts @@ -1,4 +1,4 @@ -import { Dictionary } from "../../Types/types"; +import { Dictionary } from "../Types/types"; /* This file is automatically generated */ diff --git a/src/3rdParty/HapClient/hapClient.ts b/src/HapClient/hapClient.ts similarity index 90% rename from src/3rdParty/HapClient/hapClient.ts rename to src/HapClient/hapClient.ts index d017782..d765419 100755 --- a/src/3rdParty/HapClient/hapClient.ts +++ b/src/HapClient/hapClient.ts @@ -2,35 +2,37 @@ import 'source-map-support/register'; import * as crypto from 'crypto'; import decamelize from 'decamelize'; import * as inflection from 'inflection'; -import Bonjour, { Service } from 'bonjour'; -import { EventEmitter } from 'events'; +import Bonjour from 'bonjour'; import { get, put } from 'request-promise-native'; import { Services, Characteristics } from './hap-types'; -import { HapMonitor } from './monitor'; +import { HapMonitor } from './hapMonitor'; import { IHapAccessoriesRespType, IServiceType, ICharacteristicType, IHapInstance, createDefaultCharacteristicType, IAccessoryResp } from './interfaces'; +import { log, Dictionary } from '../Types/types'; export type HapAccessoriesRespType = IHapAccessoriesRespType; export type ServiceType = IServiceType; export type CharacteristicType = ICharacteristicType; export interface IDevice { - addresses: Array - fqdn: string, - host: string, - name: string, - port: number, - protocol: "tcp" | "udp", - rawTxt: Buffer, + addresses: Array; + fqdn: string; + host: string; + name: string; + port: number; + protocol: "tcp" | "udp"; + rawTxt: Buffer; referer: { - address: string, - family: "IPv4" | "IPv6", - port: number, - size: number, - }, - subtypes: Array, - txt: any, - type: string + address: string; + family: "IPv4" | "IPv6"; + port: number; + size: number; + }; + // eslint-disable-next-line + subtypes: Array; + // eslint-disable-next-line + txt: any; + type: string; } interface IConfig { @@ -63,8 +65,8 @@ export class HapClient { constructor(opts: { pin: string; - logger?: any; - config: any; + logger: log; + config: IConfig; }) { this.pin = opts.pin; this.log = opts.logger; @@ -72,19 +74,19 @@ export class HapClient { this.config = opts.config; } - private debug(msg: any) { + private debug(msg: string): void { if (this.debugEnabled) { this.log(msg); } } - private debugErr(msg: string, err: Error) { + private debugErr(msg: string, err: Error): void { if (this.debugEnabled) { this.log(`${msg}: ${err.message}\n ${err.stack}`); } } - public refreshInstances() { + public refreshInstances(): void { if (!this.discoveryInProgress) { this.discover(); } else { @@ -99,7 +101,7 @@ export class HapClient { } public async discover(): Promise { - return new Promise((resolve) => { + return new Promise((resolve): void => { this.discoveryInProgress = true; this.browser = this.bonjour.find({ @@ -111,8 +113,9 @@ export class HapClient { this.debug(`[HapClient] Discovery :: Started`); // service found - this.browser.on('up', async (service: any) => { - let device = service as IDevice; + this.browser.on('up', async (service: Bonjour.Service) => { + const unknownService: unknown = service as unknown; + const device = unknownService as IDevice; if (!device || !device.txt) { this.debug(`[HapClient] Discovery :: Ignoring device that contains no txt records. ${JSON.stringify(device)}`); return; @@ -124,7 +127,7 @@ export class HapClient { name: device.txt.md, username: device.txt.id, port: device.port, - } + }; this.debug(`[HapClient] Discovery :: Found HAP device ${instance.displayName} with username ${instance.username}`); @@ -194,7 +197,7 @@ export class HapClient { }); } - private humanizeString(string: string) { + private humanizeString(string: string): string { return inflection.titleize(decamelize(string)); } @@ -210,7 +213,7 @@ export class HapClient { resp.accessories && resp.accessories.forEach((accessory: IAccessoryResp) => { accessory.instance = instance; accessories.push(accessory); - }) + }); } catch (e) { if (this.log) { this.debugErr(`[HapClient] [${instance.displayName} - ${instance.ipAddress}:${instance.port} (${instance.username})] Failed to connect`, e); @@ -236,7 +239,7 @@ export class HapClient { /* Parse Accessory Information */ const accessoryInformationService = accessory.services.find(x => x.type === Services.AccessoryInformation); - const accessoryInformation: { [key: string]: any } = {}; + const accessoryInformation: Dictionary = {}; if (accessoryInformationService && accessoryInformationService.characteristics) { accessoryInformationService.characteristics.forEach((c) => { @@ -272,7 +275,7 @@ export class HapClient { uuid: c.type, type: Characteristics[c.type], serviceType: Services[s.type], - serviceName: serviceName!.value.toString(), + serviceName: serviceName && serviceName.value ? serviceName.value.toString() : "Service name not found", description: c.description, value: c.value, format: c.format, @@ -307,7 +310,7 @@ export class HapClient { .digest('hex'); /* Helper function to trigger a call to the accessory to get all the characteristic values */ - service.refreshCharacteristics = () => { + service.refreshCharacteristics = (): Promise => { return this.refreshServiceCharacteristics.bind(this)(service); }; @@ -318,7 +321,7 @@ export class HapClient { /* Helper function to returns a characteristic by it's type name */ service.getCharacteristic = (type: string): ICharacteristicType => { - let characteristic = service.serviceCharacteristics.find(c => c.type === type); + const characteristic = service.serviceCharacteristics.find(c => c.type === type); return characteristic ? characteristic : createDefaultCharacteristicType(); }; @@ -345,7 +348,7 @@ export class HapClient { } public getService(iid: number): Promise { - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve, reject): Promise => { try { const services = await this.getAllServices(); return resolve(services.find(x => x.iid === iid)); @@ -357,7 +360,7 @@ export class HapClient { } public async getServiceByName(serviceName: string): Promise { - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve, reject): Promise => { try { const services = await this.getAllServices(); return resolve(services.find(x => x.serviceName === serviceName)); @@ -379,7 +382,9 @@ export class HapClient { resp.characteristics.forEach((charType: ICharacteristicType) => { const characteristic = service.serviceCharacteristics.find(x => x.iid === charType.iid && x.aid === service.aid); - characteristic!.value = charType.value; + if (characteristic) { + characteristic.value = charType.value; + } }); return service; @@ -435,6 +440,6 @@ export class HapClient { } } - return characteristic + return characteristic; } } diff --git a/src/3rdParty/HapClient/monitor.ts b/src/HapClient/hapMonitor.ts similarity index 86% rename from src/3rdParty/HapClient/monitor.ts rename to src/HapClient/hapMonitor.ts index 3509094..0b56a95 100755 --- a/src/3rdParty/HapClient/monitor.ts +++ b/src/HapClient/hapMonitor.ts @@ -2,15 +2,16 @@ import { EventEmitter } from 'events'; import { IServiceType, IHapEvInstance } from './interfaces'; import { createConnection, parseMessage } from './eventedHttpClient'; import { CharacteristicType } from './hapClient'; +import { log } from '../Types/types'; export class HapMonitor extends EventEmitter { private pin: string; private evInstances: IHapEvInstance[]; private services: IServiceType[]; - private logger: any; - private debug: any; + private logger: log; + private debug: log; - constructor(logger: any, debug: any, pin: string, services: IServiceType[]) { + constructor(logger: log, debug: log, pin: string, services: IServiceType[]) { super(); this.logger = logger; this.debug = debug; @@ -28,7 +29,7 @@ export class HapMonitor extends EventEmitter { /** * Start monitoring */ - public start() { + public start(): void { for (const instance of this.evInstances) { instance.socket = createConnection(instance, this.pin, { characteristics: instance.evCharacteristics }); @@ -40,7 +41,7 @@ export class HapMonitor extends EventEmitter { if (message.statusCode === 401) { if (this.logger) { - this.logger.warn(`[HapClient] [${instance.ipAddress}:${instance.port} (${instance.username})] ` + + this.logger(`[HapClient] [${instance.ipAddress}:${instance.port} (${instance.username})] ` + `${message.statusCode} ${message.statusMessage} - make sure Homebridge pin for this instance is set to ${this.pin}.`); } } @@ -71,7 +72,7 @@ export class HapMonitor extends EventEmitter { }); // push update to listeners - this.emit('service-update', response.filter((x: any) => x)); + this.emit('service-update', response.filter((x: unknown) => x)); } } catch (e) { // do nothing @@ -84,7 +85,7 @@ export class HapMonitor extends EventEmitter { /** * Stop monitoring. */ - public stop() { + public stop(): void { for (const instance of this.evInstances) { if (instance.socket) { try { @@ -97,7 +98,7 @@ export class HapMonitor extends EventEmitter { } } - private parseServices() { + private parseServices(): void { // get a list of characteristics we can watch for each instance for (const service of this.services) { const evCharacteristics = service.serviceCharacteristics.filter(x => x.perms.includes('ev')); @@ -113,8 +114,10 @@ export class HapMonitor extends EventEmitter { const instance = this.evInstances.find(x => x.username === service.instance.username); for (const evCharacteristic of evCharacteristics) { - if (!instance!.evCharacteristics!.find(x => x.aid === service.aid && x.iid === evCharacteristic.iid)) { - instance!.evCharacteristics!.push({ aid: service.aid, iid: evCharacteristic.iid, ev: true }); + if (instance && + instance.evCharacteristics && + !instance.evCharacteristics.find(x => x.aid === service.aid && x.iid === evCharacteristic.iid)) { + instance.evCharacteristics.push({ aid: service.aid, iid: evCharacteristic.iid, ev: true }); } } } diff --git a/src/3rdParty/HapClient/interfaces.ts b/src/HapClient/interfaces.ts similarity index 100% rename from src/3rdParty/HapClient/interfaces.ts rename to src/HapClient/interfaces.ts diff --git a/src/Types/types.ts b/src/Types/types.ts index f226c24..1e731eb 100644 --- a/src/Types/types.ts +++ b/src/Types/types.ts @@ -1 +1,14 @@ -export type Dictionary = { [key: string]: T }; \ No newline at end of file +import { EventEmitter } from "events"; + +export type Dictionary = { [key: string]: T }; + +export type log = (msg: string) => void; + +export type Homebridge = { + registerPlatform: ( + platformName: string, + platformExtension: string, + platformClass: new (log: log, config: {}, api: EventEmitter) => void, + someBool: boolean + ) => void; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2b07647..7c94d2d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,65 +1,37 @@ -import { HapClient } from "./3rdParty/HapClient/hapClient"; -import { HapMonitor } from "./3rdParty/HapClient/monitor"; +import { log, Homebridge } from './Types/types'; +import { EventEmitter } from 'events'; -let Accessory: any; -let Homebridge: any; +class AutomationPlatform { + private log: log; + private config: {} = {}; + private api: EventEmitter; + + constructor(log: log, config: {}, api: EventEmitter) { + this.log = log; + this.config = config; + this.api = api; + this.log('INFO - Registering automation platform'); + this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this)); + } + + /** + * Handler for didFinishLaunching + * Happens after constructor + */ + private didFinishLaunching(): void { + //No external accessories to publish + } +} /** * Main entry. * @param homebridge */ -export default function (homebridge: any) { - Homebridge = homebridge; - Accessory = homebridge.platformAccessory; +export default function (homebridge: Homebridge): void { homebridge.registerPlatform( 'ml-automation', 'automation', AutomationPlatform, true ); -}; - -class AutomationPlatform { - log: any = {}; - config: any = {}; - api: any; - client: HapClient; - - constructor(log: any, config: any, api: any) { - this.log = log; - this.config = config; - this.api = api; - this.log('INFO - Registering automation platform'); - this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this)); - - this.client = new HapClient({ - pin: "031-45-154", - logger: log, - config: config - }); - - this.client.discover().then(async () => { - let asdf = await this.client.getAccessories(); - let asdff = "asdf"; - }) - } - - - - - /** - * Handler for didFinishLaunching - * Happens after constructor - */ - didFinishLaunching() { - //No external accessories to publish - } - - /** - * Called by homebridge to gather accessories. - * @param callback - */ - accessories(callback: (accessories: Array) => void) { - - } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/services/monitor.ts b/src/services/monitor.ts new file mode 100644 index 0000000..19a3667 --- /dev/null +++ b/src/services/monitor.ts @@ -0,0 +1,24 @@ +import { HapClient } from "../HapClient/hapClient"; +import { log } from '../Types/types'; +import { singleton } from 'tsyringe'; + +export interface IMonitorProps { + log: log; +} + +@singleton() +export class Monitor { + private log: log; + private api: any; + private client: HapClient; + + constructor(props: IMonitorProps) { + this.log = props.log; + + this.client = new HapClient({ + pin: "031-45-154", + logger: this.log, + config: {} + }); + } +} \ No newline at end of file