Skip to content

Commit

Permalink
v2.10.1 (#854)
Browse files Browse the repository at this point in the history
## [Version 2.10.1](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v2.10.1) (2023-11-01)

## What's Changed

- Added webhook event listener for Bot, Ceiling Light, Color Bulb, Contact, Curtain, IOSensor, Light Strip, Lock, Motion, Plug, & Robot Vacuum Cleaner
- Added Webhook config to Plugin Config UI.

**Full Changelog**: <v2.10.0....v2.10.1>
  • Loading branch information
donavanbecker authored Nov 2, 2023
1 parent c34149d commit a5bf9c8
Show file tree
Hide file tree
Showing 18 changed files with 457 additions and 12 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

All notable changes to this project will be documented in this file. This project uses [Semantic Versioning](https://semver.org/)

## [Version 2.10.1](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v2.10.1) (2023-11-01)

## What's Changed

- Added webhook event listener for Bot, Ceiling Light, Color Bulb, Contact, Curtain, IOSensor, Light Strip, Lock, Motion, Plug, & Robot Vacuum Cleaner
- Added Webhook config to Plugin Config UI.

**Full Changelog**: <https://github.com/OpenWonderLabs/homebridge-switchbot/compare/v2.10.0....v2.10.1>

## [Version 2.10.0](https://github.com/OpenWonderLabs/homebridge-switchbot/releases/tag/v2.10.0) (2023-10-31)

## What's Changed
Expand Down
14 changes: 14 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@
"functionBody": "return (model.options && model.options.devices && model.options.devices[arrayIndices].deviceId && !model.options.devices[arrayIndices].hide_device && model.options.devices[arrayIndices].configDeviceType !== 'Hub 2');"
}
},
"webhook": {
"title": "Enable Webhook",
"type": "boolean",
"condition": {
"functionBody": "return (model.options && model.options.devices && model.options.devices[arrayIndices].deviceId && !model.options.devices[arrayIndices].hide_device && (model.options.devices[arrayIndices].connectionType === 'OpenAPI' || model.options.devices[arrayIndices].connectionType === 'BLE/OpenAPI'));"
}
},
"customBLEaddress": {
"title": "Custom BLE Address",
"type": "string",
Expand Down Expand Up @@ -1433,6 +1440,11 @@
},
"uniqueItems": true
},
"webhookURL": {
"title": "Webhook URL",
"type": "string",
"placeholder": "http://${FQDN}:${PORT}/${PATH}"
},
"refreshRate": {
"title": "Refresh Rate",
"type": "number",
Expand Down Expand Up @@ -1516,6 +1528,7 @@
"options.devices[].hide_device",
"options.devices[].configDeviceType",
"options.devices[].connectionType",
"options.devices[].webhook",
"options.devices[].hub.hide_temperature",
"options.devices[].hub.hide_humidity",
"options.devices[].hub.hide_lightsensor",
Expand Down Expand Up @@ -1621,6 +1634,7 @@
"expandable": true,
"expanded": false,
"items": [
"options.webhookURL",
{
"type": "help",
"helpvalue": "<h5>Refresh Rate</h5><em class='primary-text'>Refresh Rate indicates the number of seconds between polls of SwitchBot API.</em>"
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"displayName": "Homebridge SwitchBot",
"name": "@switchbot/homebridge-switchbot",
"version": "2.10.0",
"version": "2.10.1",
"description": "The [Homebridge](https://homebridge.io) SwitchBot plugin allows you to access your [SwitchBot](https://www.switch-bot.com) device(s) from HomeKit.",
"author": "SwitchBot <[email protected]> (https://github.com/SwitchBot)",
"license": "ISC",
Expand Down
23 changes: 23 additions & 0 deletions src/device/blindtilt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,29 @@ export class BlindTilt {
await this.refreshStatus();
});

//regisiter webhook event handler
if (this.device.webhook) {
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
try {
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Please Submit Logs: ` + 'https://tinyurl.com/SwitchBotBug');
/*const { temperature, humidity } = context;
const { CurrentTemperature, CurrentRelativeHumidity } = this;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
'(temperature, humidity) = ' +
`Webhook:(${temperature}, ${humidity}), ` +
`current:(${CurrentTemperature}, ${CurrentRelativeHumidity})`);
this.CurrentRelativeHumidity = humidity;
this.CurrentTemperature = temperature;
this.updateHomeKitCharacteristics();*/
} catch (e: any) {
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
+ `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
}
};
}

// update slide progress
interval(this.updateRate * 1000)
//.pipe(skipWhile(() => this.blindTiltUpdateInProgress))
Expand Down
23 changes: 23 additions & 0 deletions src/device/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,29 @@ export class Bot {
await this.refreshStatus();
});

//regisiter webhook event handler
if (this.device.webhook) {
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
try {
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
const { power, battery, deviceMode } = context;
const { On, BatteryLevel, botMode } = this;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
'(power, battery, deviceMode) = ' +
`Webhook:(${power}, ${battery}, ${deviceMode}), ` +
`current:(${On}, ${BatteryLevel}, ${botMode})`);
this.On = power;
this.BatteryLevel = battery;
this.botMode = deviceMode;
this.updateHomeKitCharacteristics();
} catch (e: any) {
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
+ `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
}
};
}

// Watch for Bot change events
// We put in a debounce of 1000ms so we don't make duplicate calls
this.doBotUpdate
Expand Down
23 changes: 23 additions & 0 deletions src/device/ceilinglight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,29 @@ export class CeilingLight {
await this.refreshStatus();
});

//regisiter webhook event handler
if (this.device.webhook) {
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
try {
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
const { powerState, brightness, colorTemperature } = context;
const { On, Brightness, ColorTemperature } = this;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
'(powerState, brightness, colorTemperature) = ' +
`Webhook:(${powerState}, ${brightness}, ${colorTemperature}), ` +
`current:(${On}, ${Brightness}, ${ColorTemperature})`);
this.On = powerState === 'ON' ? true : false;
this.Brightness = brightness;
this.ColorTemperature = colorTemperature;
this.updateHomeKitCharacteristics();
} catch (e: any) {
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
+ `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
}
};
}

// Watch for Bulb change events
// We put in a debounce of 100ms so we don't make duplicate calls
this.doCeilingLightUpdate
Expand Down
43 changes: 43 additions & 0 deletions src/device/colorbulb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,49 @@ export class ColorBulb {
await this.refreshStatus();
});

//regisiter webhook event handler
if (this.device.webhook) {
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
try {
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
const { powerState, brightness, color, colorTemperature } = context;
const { On, Brightness, Hue, Saturation, ColorTemperature } = this;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
'(powerState, brightness, color, colorTemperature) = ' +
`Webhook:(${powerState}, ${brightness}, ${color}, ${colorTemperature}), ` +
`current:(${On}, ${Brightness}, ${Hue}, ${Saturation}, ${ColorTemperature})`);
this.On = powerState === 'ON' ? true : false;
this.Brightness = brightness;

this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} color: ${JSON.stringify(color)}`);
const [red, green, blue] = color!.split(':');
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} red: ${JSON.stringify(red)}`);
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} green: ${JSON.stringify(green)}`);
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`);

const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue));
this.debugLog(
`${this.device.deviceType}: ${this.accessory.displayName}` + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`,
);

// Hue
this.Hue = hue;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${this.Hue}`);

// Saturation
this.Saturation = saturation;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${this.Saturation}`);

this.ColorTemperature = colorTemperature;
this.updateHomeKitCharacteristics();
} catch (e: any) {
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
+ `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
}
};
}

// Watch for Bulb change events
// We put in a debounce of 100ms so we don't make duplicate calls
this.doColorBulbUpdate
Expand Down
25 changes: 25 additions & 0 deletions src/device/contact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,31 @@ export class Contact {
.subscribe(async () => {
await this.refreshStatus();
});

//regisiter webhook event handler
if (this.device.webhook) {
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
try {
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
const { detectionState, brightness, openState } = context;
const { MotionDetected, CurrentAmbientLightLevel, ContactSensorState } = this;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
'(detectionState, brightness, openState) = ' +
`Webhook:(${detectionState}, ${brightness}, ${openState}), ` +
`current:(${MotionDetected}, ${CurrentAmbientLightLevel}, ${ContactSensorState})`);
this.set_minLux = this.minLux();
this.set_maxLux = this.maxLux();
this.MotionDetected = detectionState === 'DETECTED' ? true : false;
this.CurrentAmbientLightLevel = brightness === 'bright' ? this.set_maxLux : this.set_minLux;
this.ContactSensorState = openState === 'open' ? 1 : 0;
this.updateHomeKitCharacteristics();
} catch (e: any) {
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
+ `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
}
};
}
}

/**
Expand Down
22 changes: 22 additions & 0 deletions src/device/curtain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,28 @@ export class Curtain {
await this.refreshStatus();
});

//regisiter webhook event handler
if (this.device.webhook) {
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} is listening webhook.`);
this.platform.webhookEventHandler[this.device.deviceId] = async (context) => {
try {
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} received Webhook: ${JSON.stringify(context)}`);
const { slidePosition, battery } = context;
const { CurrentPosition, BatteryLevel } = this;
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ` +
'(slidePosition, battery) = ' +
`Webhook:(${slidePosition}, ${battery}), ` +
`current:(${CurrentPosition}, ${BatteryLevel})`);
this.CurrentPosition = slidePosition;
this.BatteryLevel = battery;
this.updateHomeKitCharacteristics();
} catch (e: any) {
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} `
+ `failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
}
};
}

// update slide progress
interval(this.updateRate * 1000)
//.pipe(skipWhile(() => this.curtainUpdateInProgress))
Expand Down
Loading

0 comments on commit a5bf9c8

Please sign in to comment.