From 70e88aa7c3eca0dc2f57f6ddc6dee7e391b2b269 Mon Sep 17 00:00:00 2001 From: Johann Richard <189003+johannrichard@users.noreply.github.com> Date: Sat, 28 Nov 2020 14:12:20 +0100 Subject: [PATCH] feat(plugin): stability & reliability improvements - simplify device updates - allows updating device info (core info) via platform - implements (better) device recovery - implements better error handling for devices - streamlines code - streamlines accessory interfaces & methods - other small chores - implements fixes #3, #103, #116, #123, #135 --- package.json | 1 - src/dingzAccessory.ts | 109 +++++++++---------------------- src/lib/dingzDaBaseAccessory.ts | 41 ++++++++++-- src/lib/libs.d.ts | 1 + src/myStromButtonAccessory.ts | 4 +- src/myStromLightbulbAccessory.ts | 83 ++++++++++------------- src/myStromPIRAccessory.ts | 26 ++++---- src/myStromSwitchAccessory.ts | 44 ++++++++----- src/platform.ts | 57 ++++++++++------ yarn.lock | 13 ---- 10 files changed, 173 insertions(+), 206 deletions(-) diff --git a/package.json b/package.json index 7a2210b..af7160c 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "iot" ], "dependencies": { - "@the-/jitter": "^15.4.0", "@types/node": "^14.0.13", "@types/node-fetch": "^2.5.7", "abort-controller": "^3.0.0", diff --git a/src/dingzAccessory.ts b/src/dingzAccessory.ts index 282f419..2a6684c 100644 --- a/src/dingzAccessory.ts +++ b/src/dingzAccessory.ts @@ -161,11 +161,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { // dingz has a Motion sensor -- let's create it this.addMotionService(); } else { - this.log.info( - 'Your dingz', - this.accessory.displayName, - 'has no Motion sensor.', - ); + this.log.info('This dingz has no Motion sensor.'); } // dingz has a temperature sensor and an LED, // make these available here @@ -269,7 +265,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { // Get updated device info and update the corresponding values // TODO: #103, #116, #120, #123 -- fetch state for all device elements - private getDeviceStateUpdate() { + protected getDeviceStateUpdate() { this.getDeviceState() .then((state) => { if (typeof state !== 'undefined') { @@ -277,7 +273,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { // Update reachability -- obviously, we're online again this.isReachable = true; this.log.warn( - `Device --> ${this.device.name} (${this.device.address}) --> recovered from unreachable state`, + `Device --> ${this.accessory.displayName} (${this.device.address}) --> recovered from unreachable state`, ); } // Outputs @@ -344,19 +340,6 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback(null, currentTemperature); } - /* - * This method is optional to implement. It is called when HomeKit ask to identify the accessory. - * Typical this only ever happens at the pairing process. - */ - identify(): void { - this.log.info( - 'Identify! -> Who am I? I am', - this.accessory.displayName, - '-> MAC:', - this.device.mac, - ); - } - private addLightSensorService() { // Add the LightSensor that's integrated in the dingz // API: /api/v1/light @@ -376,7 +359,6 @@ export class DingzAccessory extends DingzDaBaseAccessory { private updateLightSensor(lightService: Service) { const intensity: number = this.dingzStates.Brightness; - this.log.warn(this.device.name, 'Brightness ->', intensity); lightService .getCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel) .updateValue(intensity); @@ -560,14 +542,12 @@ export class DingzAccessory extends DingzDaBaseAccessory { (mac, action: ButtonAction, button: ButtonId | '5') => { if (mac === this.device.mac && button) { this.log.debug( - `Button ${button} of ${this.device.name} pressed -> ${action}, MAC: ${mac} (This: ${this.device.mac})`, + `Button ${button} pressed -> ${action}, MAC: ${mac} (This: ${this.device.mac})`, ); if (button === '5') { // PUSH MOTION if (!(this.platform.config.motionPoller ?? true)) { - this.log.debug( - `Button ${button} of ${this.device.name} Motion -> ${action}`, - ); + this.log.debug(`Button ${button} Motion -> ${action}`); this.log.debug('Motion Update from CALLBACK'); this.motionService ?.getCharacteristic(this.platform.Characteristic.MotionDetected) @@ -593,7 +573,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { ) .updateValue(this.dingzStates.Buttons[button].state); this.log.info( - `Button ${button} of ${this.device.name} (${service?.displayName}) pressed -> ${action}`, + `Button ${button} (${service?.displayName}) pressed -> ${action}`, ); // Immediately update states after button pressed @@ -679,14 +659,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback: CharacteristicGetCallback, ) { const currentState = this.dingzStates.Buttons[button].state; - this.log.info( - 'Get Switch State of', - this.device.name, - '->', - button, - '-> state:', - currentState, - ); + this.log.info('Get Switch State of ->', button, '-> state:', currentState); callback(null, currentState); } @@ -696,14 +669,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.dingzStates.Buttons[button].state = value as ButtonState; - this.log.info( - 'Set Switch State of', - this.device.name, - '->', - button, - '-> state:', - value, - ); + this.log.info('Set Switch State of ->', button, '-> state:', value); callback(null); } @@ -1088,7 +1054,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { this.services.push(this.motionService); // Only check for motion if we have a PIR and set the Interval if (this.platform.config.motionPoller ?? true) { - this.log.info('Motion POLLING of', this.device.name, 'enabled'); + this.log.info('Motion POLLING enabled'); const motionInterval: NodeJS.Timer = setInterval(() => { this.getDeviceMotion() .then((data) => { @@ -1106,8 +1072,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { } } else { throw new DeviceNotReachableError( - `Device can not be reached -> - ${this.device.name}-> ${this.device.address}`, + `Device can not be reached -> ${this.accessory.displayName}-> ${this.device.address}`, ); } }) @@ -1386,15 +1351,12 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.dingzStates.LED.on = value as boolean; - const state = this.dingzStates.LED; - const color = `${state.hue};${state.saturation};${state.value}`; - this.setDeviceLED({ isOn: state.on, color: color }); - callback(null); + this.setDeviceLED(callback); } private getLEDOn(callback: CharacteristicGetCallback) { const isOn = this.dingzStates.LED.on; - callback(null, isOn); + callback(this.isReachable ? null : new Error(), isOn); } private setLEDHue( @@ -1402,14 +1364,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.dingzStates.LED.hue = value as number; - - const state: DingzLEDState = this.dingzStates.LED; - const color = `${state.hue};${state.saturation};${state.value}`; - this.setDeviceLED({ - isOn: state.on, - color: color, - }); - callback(null); + this.setDeviceLED(callback); } private setLEDSaturation( @@ -1417,14 +1372,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.dingzStates.LED.saturation = value as number; - - const state: DingzLEDState = this.dingzStates.LED; - const color = `${state.hue};${state.saturation};${state.value}`; - this.setDeviceLED({ - isOn: state.on, - color: color, - }); - callback(null); + this.setDeviceLED(callback); } private setLEDBrightness( @@ -1432,14 +1380,7 @@ export class DingzAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.dingzStates.LED.value = value as number; - - const state: DingzLEDState = this.dingzStates.LED; - const color = `${state.hue};${state.saturation};${state.value}`; - this.setDeviceLED({ - isOn: state.on, - color: color, - }); - callback(null); + this.setDeviceLED(callback); } // Get Input & Dimmer Config @@ -1566,17 +1507,19 @@ export class DingzAccessory extends DingzDaBaseAccessory { // TODO: Feedback on API doc /** * Set the LED on the dingz - * @param isOn: on/off state - * @param color color to set the LED to + * @param callback: Characteristic callback */ - private setDeviceLED({ isOn, color }: { isOn: boolean; color: string }) { + private setDeviceLED(callback: CharacteristicSetCallback) { + const state: DingzLEDState = this.dingzStates.LED; + const color = `${state.hue};${state.saturation};${state.value}`; + const setLEDEndpoint = `${this.baseUrl}/api/v1/led/set`; this.request .post( setLEDEndpoint, qs.stringify( { - action: isOn ? 'on' : 'off', + action: state.on ? 'on' : 'off', color: color, mode: 'hsv', // Fixed for the time being ramp: 150, @@ -1584,7 +1527,15 @@ export class DingzAccessory extends DingzDaBaseAccessory { { encode: false }, ), ) - .catch(this.handleRequestErrors.bind(this)); + .catch(this.handleRequestErrors.bind(this)) + .finally(() => { + // make sure we callback + if (!this.isReachable) { + callback(new Error()); + } else { + callback(null); + } + }); } // Get the current state diff --git a/src/lib/dingzDaBaseAccessory.ts b/src/lib/dingzDaBaseAccessory.ts index 683f268..6492d97 100644 --- a/src/lib/dingzDaBaseAccessory.ts +++ b/src/lib/dingzDaBaseAccessory.ts @@ -37,7 +37,7 @@ export class DingzDaBaseAccessory { this.device = this.accessory.context.device; this.baseUrl = `http://${this.device.address}`; - this.log = new DingzLogger(this.device.name, platform.log); + this.log = new DingzLogger(this.accessory.displayName, platform.log); this.request = axios.create({ baseURL: this.baseUrl, timeout: RETRY_TIMEOUT, @@ -62,6 +62,11 @@ export class DingzDaBaseAccessory { ); }); + this.platform.eb.on( + PlatformEvent.REQUEST_STATE_UPDATE, + this.getDeviceStateUpdate.bind(this), + ); + // Register listener for updated device info (e.g. on restore with new IP) this.platform.eb.on( PlatformEvent.UPDATE_DEVICE_INFO, @@ -71,23 +76,38 @@ export class DingzDaBaseAccessory { 'Updated device info received -> update accessory address', ); - // Update core info (mainly address) - if (this.device.address !== deviceInfo.address) { + // Update core info (mainly address, maybe token too) + if ( + this.device.address !== deviceInfo.address || + this.device.token !== deviceInfo.token + ) { this.log.info( 'Accessory IP changed for', - this.device.name, + this.accessory.displayName, '-> Updating accessory from ->', this.device.address, 'to', deviceInfo.address, ); + this.accessory.displayName = this.device.name; this.device.address = deviceInfo.address; + this.device.token = deviceInfo.token; this.baseUrl = `http://${this.device.address}`; - // Set AccessoryInformation and Update its configuration + this.request.defaults = { + baseURL: this.baseUrl, + timeout: RETRY_TIMEOUT, + headers: { Token: this.device.token ?? '' }, + }; + + // update AccessoryInformation this.setAccessoryInformation(); - this.updateAccessory(); } + + // Set accessory to reachable and + // updateAccessory() + this.isReachable = true; + this.updateAccessory(); } }, ); @@ -108,6 +128,13 @@ export class DingzDaBaseAccessory { ); } + protected getDeviceStateUpdate() { + this.log.debug( + 'getDeviceStateUpdate() not implemented for', + this.device.accessoryClass, + ); + } + /** * Handler for request errors * @param e AxiosError: the error returned by this.request() @@ -134,7 +161,7 @@ export class DingzDaBaseAccessory { } } else if (e instanceof DeviceNotReachableError) { this.log.error( - `handleRequestErrors() --> ${this.device.name} (${this.device.address})`, + `handleRequestErrors() --> ${this.accessory.displayName} (${this.device.address})`, ); this.isReachable = false; } else { diff --git a/src/lib/libs.d.ts b/src/lib/libs.d.ts index e9360ad..447238f 100644 --- a/src/lib/libs.d.ts +++ b/src/lib/libs.d.ts @@ -1 +1,2 @@ declare module 'simple-color-converter'; +declare module 'is-valid-host'; diff --git a/src/myStromButtonAccessory.ts b/src/myStromButtonAccessory.ts index fcda78f..46ffb8c 100644 --- a/src/myStromButtonAccessory.ts +++ b/src/myStromButtonAccessory.ts @@ -141,9 +141,7 @@ export class MyStromButtonAccessory extends DingzDaBaseAccessory { const ProgrammableSwitchEvent = this.platform.Characteristic .ProgrammableSwitchEvent; if (buttonService) { - this.log.debug( - `Button of ${this.device.name} (${this.device.mac}) pressed -> ${action}`, - ); + this.log.debug(`Button (${this.device.mac}) pressed -> ${action}`); switch (action) { case ButtonAction.SINGLE_PRESS: buttonService diff --git a/src/myStromLightbulbAccessory.ts b/src/myStromLightbulbAccessory.ts index 10c4580..2957d80 100644 --- a/src/myStromLightbulbAccessory.ts +++ b/src/myStromLightbulbAccessory.ts @@ -105,7 +105,7 @@ export class MyStromLightbulbAccessory extends DingzDaBaseAccessory { } // Get updated device info and update the corresponding values - private getDeviceStateUpdate() { + protected getDeviceStateUpdate() { this.getDeviceReport(this.device.mac) .then((report) => { // push the new value to HomeKit @@ -157,15 +157,14 @@ export class MyStromLightbulbAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.lightbulbState.on = value as boolean; - this.setDeviceLightbulb({ isOn: this.lightbulbState.on }); - callback(null); + this.setDeviceLightbulb(callback); } private getOn(callback: CharacteristicGetCallback) { const isOn = this.lightbulbState.on; this.platform.log.debug('Get Characteristic On ->', isOn); - callback(null, isOn); + callback(this.isReachable ? null : new Error(), isOn); } private async setHue( @@ -173,18 +172,12 @@ export class MyStromLightbulbAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.lightbulbState.hue = value as number; - - const state: MyStromLightbulbReport = this.lightbulbState; - await this.setDeviceLightbulb({ - isOn: state.on, - color: `${state.hue};${state.saturation};${state.value}`, - }); - callback(null); + this.setDeviceLightbulb(callback); } private getHue(callback: CharacteristicGetCallback) { const hue: number = this.lightbulbState.hue; - callback(null, hue); + callback(this.isReachable ? null : new Error(), hue); } private async setSaturation( @@ -192,18 +185,12 @@ export class MyStromLightbulbAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.lightbulbState.saturation = value as number; - - const state: MyStromLightbulbReport = this.lightbulbState; - await this.setDeviceLightbulb({ - isOn: state.on, - color: `${state.hue};${state.saturation};${state.value}`, - }); - callback(null); + this.setDeviceLightbulb(callback); } private getSaturation(callback: CharacteristicGetCallback) { const saturation: number = this.lightbulbState.saturation; - callback(null, saturation); + callback(this.isReachable ? null : new Error(), saturation); } private async setBrightness( @@ -211,42 +198,38 @@ export class MyStromLightbulbAccessory extends DingzDaBaseAccessory { callback: CharacteristicSetCallback, ) { this.lightbulbState.value = value as number; - const state: MyStromLightbulbReport = this.lightbulbState; - await this.setDeviceLightbulb({ - isOn: state.on, - color: `${state.hue};${state.saturation};${state.value}`, - }); - callback(null); + this.setDeviceLightbulb(callback); } private getBrightness(callback: CharacteristicGetCallback) { const brightness = this.lightbulbState.value; - callback(null, brightness); + callback(this.isReachable ? null : new Error(), brightness); } // Set individual dimmer - private async setDeviceLightbulb({ - isOn, - color, - }: { - isOn: boolean; - color?: string; - }): Promise { - // Weird URL :-) + private setDeviceLightbulb(callback: CharacteristicSetCallback) { + const state: MyStromLightbulbReport = this.lightbulbState; + const color = `${state.hue};${state.saturation};${state.value}`; + const setDimmerUrl = `${this.baseUrl}/api/v1/device/${this.device.mac}`; - await DingzDaHomebridgePlatform.fetch({ - url: setDimmerUrl, - method: 'POST', - token: this.device.token, - body: qs.stringify( - { - action: isOn ? 'on' : 'off', + return this.request + .post( + setDimmerUrl, + qs.stringify({ + action: state.on ? 'on' : 'off', color: color ?? undefined, mode: color ? 'hsv' : undefined, - }, - { encode: false }, - ), - }); + }), + ) + .catch(this.handleRequestErrors.bind(this)) + .finally(() => { + // make sure we callback + if (!this.isReachable) { + callback(new Error()); + } else { + callback(null); + } + }); } private async getDeviceReport(mac: string): Promise { @@ -255,8 +238,10 @@ export class MyStromLightbulbAccessory extends DingzDaBaseAccessory { url: reportUrl, returnBody: true, token: this.device.token, - }).then((response) => { - return response[mac]; - }); + }) + .then((response) => { + return response[mac]; + }) + .catch(this.handleRequestErrors.bind(this)); } } diff --git a/src/myStromPIRAccessory.ts b/src/myStromPIRAccessory.ts index 8530041..8662ab9 100644 --- a/src/myStromPIRAccessory.ts +++ b/src/myStromPIRAccessory.ts @@ -79,7 +79,7 @@ export class MyStromPIRAccessory extends DingzDaBaseAccessory { // get the LightBulb service if it exists, otherwise create a new LightBulb service // you can create multiple services for each accessory - this.log.info('Create Motion Sensor -> ', this.device.name); + this.log.info('Create Motion Sensor'); this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor) ?? @@ -163,7 +163,7 @@ export class MyStromPIRAccessory extends DingzDaBaseAccessory { } // Get updated device info and update the corresponding values - private getDeviceStateUpdate() { + protected getDeviceStateUpdate() { this.getDeviceReport() .then((report) => { if (report) { @@ -218,7 +218,7 @@ export class MyStromPIRAccessory extends DingzDaBaseAccessory { const light: number = this.pirState?.light ?? 42; this.log.debug('Get Characteristic Ambient Light Level ->', light, ' lux'); - callback(null, light); + callback(this.isReachable ? null : new Error(), light); } /** @@ -229,7 +229,7 @@ export class MyStromPIRAccessory extends DingzDaBaseAccessory { const temperature: number = this.pirState?.temperature; this.log.debug('Get Characteristic Temperature ->', temperature, '° C'); - callback(null, temperature); + callback(this.isReachable ? null : new Error(), temperature); } /** @@ -239,21 +239,17 @@ export class MyStromPIRAccessory extends DingzDaBaseAccessory { private getMotionDetected(callback: CharacteristicGetCallback) { // set this to a valid value for MotionDetected const isMotion = this.pirState.motion; - callback(null, isMotion); + callback(this.isReachable ? null : new Error(), isMotion); } private async getDeviceReport(): Promise { const getSensorsUrl = `${this.baseUrl}/api/v1/sensors`; - const release = await this.mutex.acquire(); - try { - return await DingzDaHomebridgePlatform.fetch({ - url: getSensorsUrl, - returnBody: true, - token: this.device.token, - }); - } finally { - release(); - } + return await this.request + .get(getSensorsUrl) + .then((response) => { + return response.data; + }) + .catch(this.handleRequestErrors.bind(this)); } /* diff --git a/src/myStromSwitchAccessory.ts b/src/myStromSwitchAccessory.ts index d004a56..179f9f7 100644 --- a/src/myStromSwitchAccessory.ts +++ b/src/myStromSwitchAccessory.ts @@ -112,7 +112,7 @@ export class MyStromSwitchAccessory extends DingzDaBaseAccessory { } // Get updated device info and update the corresponding values - private getDeviceStateUpdate() { + protected getDeviceStateUpdate() { this.getDeviceReport() .then((report) => { // push the new value to HomeKit @@ -142,44 +142,52 @@ export class MyStromSwitchAccessory extends DingzDaBaseAccessory { ) { this.log.debug('Set Characteristic On ->', value); this.outletState.relay = value as boolean; - this.setDeviceState(this.outletState.relay); - callback(null); + this.setDeviceState(callback); } private getOn(callback: CharacteristicGetCallback) { const isOn = this.outletState?.relay; this.log.debug('Get Characteristic On ->', isOn); - callback(null, isOn); + callback(this.isReachable ? null : new Error(), isOn); } private getTemperature(callback: CharacteristicGetCallback) { const temperature: number = this.outletState?.temperature; this.log.debug('Get Characteristic Temperature ->', temperature, '° C'); - - callback(null, temperature); + callback(this.isReachable ? null : new Error(), temperature); } private getOutletInUse(callback: CharacteristicGetCallback) { const inUse: boolean = this.outletState?.power > 0; this.log.debug('Get Characteristic OutletInUse ->', inUse); - callback(null, inUse); + callback(this.isReachable ? null : new Error(), inUse); } - private setDeviceState(isOn: boolean) { - const relayUrl = `${this.baseUrl}/relay?state=${isOn ? '1' : '0'}`; - DingzDaHomebridgePlatform.fetch({ - url: relayUrl, - token: this.device.token, - }); + private setDeviceState(callback: CharacteristicSetCallback) { + const relayUrl = `${this.baseUrl}/relay?state=${ + this.outletState.relay ? '1' : '0' + }`; + this.request + .get(relayUrl) + .catch(this.handleRequestErrors.bind(this)) + .finally(() => { + // make sure we callback + if (!this.isReachable) { + callback(new Error()); + } else { + callback(null); + } + }); } private async getDeviceReport(): Promise { const reportUrl = `${this.baseUrl}/report`; - return await DingzDaHomebridgePlatform.fetch({ - url: reportUrl, - returnBody: true, - token: this.device.token, - }); + return await this.request + .get(reportUrl) + .then((response) => { + return response.data; + }) + .catch(this.handleRequestErrors.bind(this)); } } diff --git a/src/platform.ts b/src/platform.ts index a27f10e..affee2e 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -12,8 +12,9 @@ import axios, { AxiosRequestConfig, AxiosError } from 'axios'; import axiosRetry from 'axios-retry'; import * as bodyParser from 'body-parser'; import i4h from 'intervals-for-humans'; -import e = require('express'); +import isValidHost from 'is-valid-host'; import * as os from 'os'; +import e = require('express'); // Internal Types import { ButtonId, DingzDeviceInfo } from './lib/dingzTypes'; @@ -188,11 +189,11 @@ export class DingzDaHomebridgePlatform implements DynamicPlatformPlugin { switch (device.type) { case 'dingz': retryWithBreaker.execute(() => - this.addDingzDevice( - device.address, - device.name, - device.token ?? this.config.globalToken, - ), + this.addDingzDevice({ + address: device.address, + name: device.name, + token: device.token ?? this.config.globalToken, + }), ); break; case 'myStromSwitch': @@ -235,11 +236,15 @@ export class DingzDaHomebridgePlatform implements DynamicPlatformPlugin { } // Add one device based on address and name - private async addDingzDevice( - address: string, + private async addDingzDevice({ + address, name = 'dingz', - token?: string, - ): Promise { + token, + }: { + address: string; + name?: string; + token?: string; + }): Promise { // Run a diacovery of changed things every 10 seconds this.log.debug( `addDingzDevice() --> Add configured device -> ${name} (${address})`, @@ -830,11 +835,11 @@ export class DingzDaHomebridgePlatform implements DynamicPlatformPlugin { case DeviceTypes.DINGZ: retryWithBreaker .execute(() => { - this.addDingzDevice( - remoteInfo.address, - 'dingz', - this.config.globalToken, - ); + this.addDingzDevice({ + address: remoteInfo.address, + name: 'dingz', + token: this.config.globalToken, + }); }) .then(() => { this.discovered.set(mac, remoteInfo); @@ -917,12 +922,15 @@ export class DingzDaHomebridgePlatform implements DynamicPlatformPlugin { private callbackServer() { this.app.use(bodyParser.urlencoded()); this.app.post('/button', this.handleRequest.bind(this)); - this.app.listen(this.config.callbackPort ?? DINGZ_CALLBACK_PORT, () => - this.log.warn( - `Callback server listening for POST requests on ${ - this.config.callbackPort ?? DINGZ_CALLBACK_PORT - }... use ${this.getCallbackUrl()} as URL for your dingz or MyStrom callbacks`, - ), + this.app.listen( + this.config.callbackPort ?? DINGZ_CALLBACK_PORT, + '0.0.0.0', + () => + this.log.warn( + `Callback server listening for POST requests on ${ + this.config.callbackPort ?? DINGZ_CALLBACK_PORT + }... use ${this.getCallbackUrl()} as URL for your dingz or MyStrom callbacks`, + ), ); } @@ -943,6 +951,13 @@ export class DingzDaHomebridgePlatform implements DynamicPlatformPlugin { '-> dingz/Multi-button Action from', request.connection.remoteAddress, ); + // attempt-auto add of either a dingz + if ( + request.connection.remoteAddress && + isValidHost(request.connection.remoteAddress) + ) { + this.addDingzDevice({ address: request.connection.remoteAddress }); + } this.eb.emit( PlatformEvent.ACTION, mac, diff --git a/yarn.lock b/yarn.lock index 173d94c..925d509 100644 --- a/yarn.lock +++ b/yarn.lock @@ -178,14 +178,6 @@ dependencies: defer-to-connect "^1.0.1" -"@the-/jitter@^15.4.0": - version "15.4.0" - resolved "https://registry.yarnpkg.com/@the-/jitter/-/jitter-15.4.0.tgz#1c4121d99c25f31ca774c4fa301c25b00b9e8009" - integrity sha512-XYeFGJynlXMAz/hi/7rPIbH3j7C6vxykyaqgbrvPqC2Pg2njMZ3Yfu6xi1nhTWgQ18Cyv3VU5BWpFdWZtWyfQA== - dependencies: - asleep "^1.0.3" - debug "^4.1.1" - "@types/body-parser@*", "@types/body-parser@^1.19.0": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" @@ -485,11 +477,6 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asleep@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/asleep/-/asleep-1.0.3.tgz#a104e24ac229563c425e4ea7e75b578a19ee218e" - integrity sha1-oQTiSsIpVjxCXk6n51tXihnuIY4= - astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"