homebridge-ring 14.2.0 → 15.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/lib/base-accessory.js +2 -2
- package/lib/base-data-accessory.js +28 -11
- package/lib/base-device-accessory.js +2 -2
- package/lib/beam.js +2 -2
- package/lib/brightness-only.js +2 -2
- package/lib/camera-source.js +1 -1
- package/lib/camera.js +4 -4
- package/lib/chime.js +17 -3
- package/lib/co-alarm.js +2 -2
- package/lib/contact-sensor.js +2 -2
- package/lib/fan.js +2 -2
- package/lib/flood-freeze-sensor.js +2 -2
- package/lib/freeze-sensor.js +2 -2
- package/lib/homebridge-ui/server.js +7 -3
- package/lib/index.js +2 -2
- package/lib/intercom.js +2 -2
- package/lib/location-mode-switch.js +48 -22
- package/lib/lock.js +2 -2
- package/lib/motion-sensor.js +2 -2
- package/lib/multi-level-switch.js +2 -2
- package/lib/outlet.js +2 -2
- package/lib/panic-buttons.js +2 -2
- package/lib/ring-platform.js +30 -30
- package/lib/security-panel.js +3 -3
- package/lib/smoke-alarm.js +2 -2
- package/lib/smoke-co-listener.js +7 -4
- package/lib/switch.js +2 -2
- package/lib/temperature-sensor.js +2 -2
- package/lib/thermostat.js +2 -2
- package/lib/unknown-zwave-switch.js +2 -2
- package/lib/valve.js +2 -2
- package/lib/water-sensor.js +2 -2
- package/package.json +13 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# homebridge-ring
|
|
2
2
|
|
|
3
|
+
## 15.0.0-beta.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#1846](https://github.com/dgreif/ring/pull/1846) [`2a6371d`](https://github.com/dgreif/ring/commit/2a6371d0890e35a80bf97fb1e1ccfa2a7c283b4e) Thanks [@dgreif](https://github.com/dgreif)! - Drop Node.js 20 support and upgrade undici to 8.x. Requires Node.js 22.19.0+ (22.x), 24.x, or 26.x; earlier 22.x releases are no longer supported.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#1892](https://github.com/dgreif/ring/pull/1892) [`8c9b637`](https://github.com/dgreif/ring/commit/8c9b63740f9d1bcd30a12922325eb58ac68e4cf9) Thanks [@dgreif](https://github.com/dgreif)! - Prevent failed volume, brightness, dimmer, and fan-speed writes from crashing Homebridge. Log failures and restore the last reported Ring level without overwriting newer requests.
|
|
12
|
+
|
|
13
|
+
- [#1886](https://github.com/dgreif/ring/pull/1886) [`78ae341`](https://github.com/dgreif/ring/commit/78ae341e990aa18517402a4e3809a51d3692678d) Thanks [@dgreif](https://github.com/dgreif)! - Never overwrite the stored refresh token when Ring's oauth response has no `refresh_token`. Previously, an undecodable response (for example Node.js 26 with an older undici) saved a token without `rt`, which caused permanent `invalid_grant` errors until a new token was generated
|
|
14
|
+
|
|
15
|
+
- [#1871](https://github.com/dgreif/ring/pull/1871) [`c72026d`](https://github.com/dgreif/ring/commit/c72026d72c7b9ccb9ef45b4f64c6affd86d85df2) Thanks [@dgreif](https://github.com/dgreif)! - Restore the reported location mode when a HomeKit mode change fails, without overwriting newer requests. Preserve pending Home mode targets until Ring confirms them.
|
|
16
|
+
|
|
17
|
+
- [#1746](https://github.com/dgreif/ring/pull/1746) [`25c6ec6`](https://github.com/dgreif/ring/commit/25c6ec63a9826f42f3f4269d0c2aad6f1e0e4185) Thanks [@kzaky](https://github.com/kzaky)! - Redact the 2FA code from the homebridge-ui server log on token exchange. Codes are short-lived and single-use, but logs are frequently pasted into bug reports, so removing the value from the log is a small defensive improvement.
|
|
18
|
+
|
|
19
|
+
- [#1838](https://github.com/dgreif/ring/pull/1838) [`c78c8b3`](https://github.com/dgreif/ring/commit/c78c8b3fadb0650d210d1220d2724309aec02611) Thanks [@dgreif](https://github.com/dgreif)! - Updated dependencies
|
|
20
|
+
|
|
21
|
+
- [#1840](https://github.com/dgreif/ring/pull/1840) [`5e4afd4`](https://github.com/dgreif/ring/commit/5e4afd43e88802e62bfc8acab743433d9bfaabfa) Thanks [@dgreif](https://github.com/dgreif)! - Bump werift to 0.26.0 (clears `ip` audit) and accept partial ICE candidates for Ring signaling
|
|
22
|
+
- Updated dependencies [[`e368e26`](https://github.com/dgreif/ring/commit/e368e26f789f4ca2093ac015dcec4bc9ce181d62), [`003c0d0`](https://github.com/dgreif/ring/commit/003c0d0740cedd3c393ce86baf628d7e5bc26c86), [`98f0cb3`](https://github.com/dgreif/ring/commit/98f0cb3f87473c168f4cb369ae26d486030e059e), [`bb781fe`](https://github.com/dgreif/ring/commit/bb781fe5ea8616c568a6f7d8e05a0d15fd472104), [`78ae341`](https://github.com/dgreif/ring/commit/78ae341e990aa18517402a4e3809a51d3692678d), [`2a6371d`](https://github.com/dgreif/ring/commit/2a6371d0890e35a80bf97fb1e1ccfa2a7c283b4e), [`c78c8b3`](https://github.com/dgreif/ring/commit/c78c8b3fadb0650d210d1220d2724309aec02611), [`5e4afd4`](https://github.com/dgreif/ring/commit/5e4afd43e88802e62bfc8acab743433d9bfaabfa)]:
|
|
23
|
+
- ring-client-api@15.0.0-beta.0
|
|
24
|
+
|
|
25
|
+
## 14.3.0
|
|
26
|
+
|
|
27
|
+
### Minor Changes
|
|
28
|
+
|
|
29
|
+
- [#1706](https://github.com/dgreif/ring/pull/1706) [`8381520`](https://github.com/dgreif/ring/commit/8381520f86d7d7813f670e3887b43d92542f0a41) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Add support for Ring Chime Pro nightlight
|
|
30
|
+
|
|
31
|
+
- [#1705](https://github.com/dgreif/ring/pull/1705) [`5360c16`](https://github.com/dgreif/ring/commit/5360c16f91d8680a20e68b2dd28e63cc0108c241) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Block streaming from cameras based on location mode settings. This may prevent you from streaming in cases where you could previously stream in HomeKit but not the Ring app.
|
|
32
|
+
|
|
33
|
+
- [#1707](https://github.com/dgreif/ring/pull/1707) [`5a8c844`](https://github.com/dgreif/ring/commit/5a8c844ffe4adc39e8a517628b26611fac36ef0a) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Add support for Kidde Ring Smoke + CO Alarm device (comp.bluejay.sensor_bluejay_wsc). Note, this has not been tested and may not be working yet.
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- [`875f024`](https://github.com/dgreif/ring/commit/875f024c5f27c55785d7250bc78eff0fda0a4aa9) Thanks [@dgreif](https://github.com/dgreif)! - Update dependencies
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [[`8381520`](https://github.com/dgreif/ring/commit/8381520f86d7d7813f670e3887b43d92542f0a41), [`875f024`](https://github.com/dgreif/ring/commit/875f024c5f27c55785d7250bc78eff0fda0a4aa9), [`5360c16`](https://github.com/dgreif/ring/commit/5360c16f91d8680a20e68b2dd28e63cc0108c241), [`5a8c844`](https://github.com/dgreif/ring/commit/5a8c844ffe4adc39e8a517628b26611fac36ef0a)]:
|
|
40
|
+
- ring-client-api@14.3.0
|
|
41
|
+
|
|
3
42
|
## 14.2.0
|
|
4
43
|
|
|
5
44
|
### Minor Changes
|
package/lib/base-accessory.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { hap } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
2
|
import { shareReplay, take } from 'rxjs/operators';
|
|
3
3
|
import { firstValueFrom } from 'rxjs';
|
|
4
|
-
import { debug } from
|
|
4
|
+
import { debug } from './config.js';
|
|
5
5
|
import { logError, logInfo } from 'ring-client-api/util';
|
|
6
6
|
function isServiceInstance(serviceType) {
|
|
7
7
|
return typeof serviceType === 'object';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { BaseAccessory } from
|
|
2
|
-
import { Subject } from 'rxjs';
|
|
1
|
+
import { BaseAccessory } from './base-accessory.js';
|
|
2
|
+
import { merge, Subject } from 'rxjs';
|
|
3
3
|
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
|
|
4
4
|
import { logError } from 'ring-client-api/util';
|
|
5
5
|
export class BaseDataAccessory extends BaseAccessory {
|
|
6
6
|
registerCharacteristic({ characteristicType, serviceType, getValue, setValue, setValueDebounceTime = 0, name, requestUpdate, serviceSubType, }) {
|
|
7
|
-
const service = this.getService(serviceType, name, serviceSubType), characteristic = service.getCharacteristic(characteristicType), { device } = this;
|
|
7
|
+
const service = this.getService(serviceType, name, serviceSubType), characteristic = service.getCharacteristic(characteristicType), { device } = this, onValue = new Subject();
|
|
8
8
|
if (requestUpdate) {
|
|
9
9
|
// Only register for GET if an async request should be made to get an updated value
|
|
10
10
|
characteristic.on("get" /* CharacteristicEventTypes.GET */, (callback) => {
|
|
@@ -21,10 +21,17 @@ export class BaseDataAccessory extends BaseAccessory {
|
|
|
21
21
|
if (setValue && setValueDebounceTime) {
|
|
22
22
|
const onValueToSet = new Subject();
|
|
23
23
|
characteristic.on("set" /* CharacteristicEventTypes.SET */, (newValue, callback) => {
|
|
24
|
+
onValue.next(newValue);
|
|
24
25
|
onValueToSet.next(newValue);
|
|
25
26
|
callback();
|
|
26
27
|
});
|
|
27
|
-
onValueToSet
|
|
28
|
+
onValueToSet
|
|
29
|
+
.pipe(debounceTime(setValueDebounceTime))
|
|
30
|
+
.subscribe((value) => {
|
|
31
|
+
Promise.resolve()
|
|
32
|
+
.then(() => setValue(value))
|
|
33
|
+
.catch(logError);
|
|
34
|
+
});
|
|
28
35
|
}
|
|
29
36
|
else if (setValue) {
|
|
30
37
|
characteristic.on("set" /* CharacteristicEventTypes.SET */, (newValue, callback) => {
|
|
@@ -32,14 +39,14 @@ export class BaseDataAccessory extends BaseAccessory {
|
|
|
32
39
|
callback();
|
|
33
40
|
});
|
|
34
41
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.pipe(map(getValue), distinctUntilChanged())
|
|
42
|
+
merge(this.device.onData.pipe(map(getValue)), onValue)
|
|
43
|
+
.pipe(distinctUntilChanged())
|
|
38
44
|
.subscribe((value) => characteristic.updateValue(value));
|
|
45
|
+
return (value) => onValue.next(value);
|
|
39
46
|
}
|
|
40
47
|
registerLevelCharacteristic({ characteristicType, serviceType, getValue, setValue, requestUpdate, }) {
|
|
41
|
-
let targetLevel;
|
|
42
|
-
this.registerCharacteristic({
|
|
48
|
+
let targetLevel, levelRequestId = 0;
|
|
49
|
+
const updateValue = this.registerCharacteristic({
|
|
43
50
|
characteristicType,
|
|
44
51
|
serviceType,
|
|
45
52
|
getValue: (data) => {
|
|
@@ -49,9 +56,19 @@ export class BaseDataAccessory extends BaseAccessory {
|
|
|
49
56
|
}
|
|
50
57
|
return targetLevel === undefined ? newLevel : targetLevel;
|
|
51
58
|
},
|
|
52
|
-
setValue: (level) => {
|
|
59
|
+
setValue: async (level) => {
|
|
60
|
+
const requestId = ++levelRequestId;
|
|
53
61
|
targetLevel = level;
|
|
54
|
-
|
|
62
|
+
try {
|
|
63
|
+
await setValue(level);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
if (requestId === levelRequestId) {
|
|
67
|
+
targetLevel = undefined;
|
|
68
|
+
updateValue(getValue(this.device.data));
|
|
69
|
+
}
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
55
72
|
},
|
|
56
73
|
setValueDebounceTime: 500,
|
|
57
74
|
requestUpdate,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { hap } from
|
|
2
|
-
import { BaseDataAccessory } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
|
+
import { BaseDataAccessory } from './base-data-accessory.js';
|
|
3
3
|
function getBatteryLevel({ batteryLevel, batteryStatus }) {
|
|
4
4
|
if (batteryLevel !== undefined) {
|
|
5
5
|
return batteryLevel;
|
package/lib/beam.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RingDeviceType } from 'ring-client-api';
|
|
2
|
-
import { hap } from
|
|
3
|
-
import { BaseDeviceAccessory } from
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
4
4
|
import { logInfo } from 'ring-client-api/util';
|
|
5
5
|
export class Beam extends BaseDeviceAccessory {
|
|
6
6
|
isLightGroup;
|
package/lib/brightness-only.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class BrightnessOnly extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
package/lib/camera-source.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hap } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
2
|
import { generateSrtpOptions, ReturnAudioTranscoder, RtpSplitter, } from '@homebridge/camera-utils';
|
|
3
3
|
import { logDebug, logError, logInfo } from 'ring-client-api/util';
|
|
4
4
|
import { debounceTime, delay, take } from 'rxjs/operators';
|
package/lib/camera.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { hap } from
|
|
2
|
-
import { BaseDataAccessory } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
|
+
import { BaseDataAccessory } from './base-data-accessory.js';
|
|
3
3
|
import { filter, map, switchMap, throttleTime } from 'rxjs/operators';
|
|
4
|
-
import { CameraSource } from
|
|
5
|
-
import { TargetValueTimer } from
|
|
4
|
+
import { CameraSource } from './camera-source.js';
|
|
5
|
+
import { TargetValueTimer } from './target-value-timer.js';
|
|
6
6
|
import { delay, logError, logInfo } from 'ring-client-api/util';
|
|
7
7
|
import { firstValueFrom } from 'rxjs';
|
|
8
8
|
export class Camera extends BaseDataAccessory {
|
package/lib/chime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { hap } from
|
|
2
|
-
import { BaseDataAccessory } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
|
+
import { BaseDataAccessory } from './base-data-accessory.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
const minutesFor24Hours = 24 * 60;
|
|
5
5
|
export class Chime extends BaseDataAccessory {
|
|
@@ -11,7 +11,7 @@ export class Chime extends BaseDataAccessory {
|
|
|
11
11
|
this.device = device;
|
|
12
12
|
this.accessory = accessory;
|
|
13
13
|
this.config = config;
|
|
14
|
-
const { Characteristic, Service } = hap, snoozeService = this.getService(Service.Switch, device.name + ' Snooze', 'snooze'), playDingService = this.getService(Service.Switch, device.name + ' Play Ding', 'play-ding'), playMotionService = this.getService(Service.Switch, device.name + ' Play Motion', 'play-motion');
|
|
14
|
+
const { Characteristic, Service } = hap, snoozeService = this.getService(Service.Switch, device.name + ' Snooze', 'snooze'), playDingService = this.getService(Service.Switch, device.name + ' Play Ding', 'play-ding'), playMotionService = this.getService(Service.Switch, device.name + ' Play Motion', 'play-motion'), hasNightlight = device.data.settings.night_light_settings !== undefined;
|
|
15
15
|
// Snooze Switch
|
|
16
16
|
this.registerCharacteristic({
|
|
17
17
|
characteristicType: Characteristic.On,
|
|
@@ -82,6 +82,20 @@ export class Chime extends BaseDataAccessory {
|
|
|
82
82
|
},
|
|
83
83
|
requestUpdate: () => device.requestUpdate(),
|
|
84
84
|
});
|
|
85
|
+
// Nightlight (if supported)
|
|
86
|
+
if (hasNightlight) {
|
|
87
|
+
const nightlightService = this.getService(Service.Lightbulb, device.name + ' Nightlight', 'nightlight');
|
|
88
|
+
this.registerCharacteristic({
|
|
89
|
+
characteristicType: Characteristic.On,
|
|
90
|
+
serviceType: nightlightService,
|
|
91
|
+
getValue: (data) => Boolean(data.settings.night_light_settings?.light_sensor_enabled),
|
|
92
|
+
setValue: (enabled) => {
|
|
93
|
+
logInfo(`${device.name} nightlight ${enabled ? 'enabled' : 'disabled'}`);
|
|
94
|
+
return device.setNightlightEnabled(enabled);
|
|
95
|
+
},
|
|
96
|
+
requestUpdate: () => device.requestUpdate(),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
85
99
|
// Accessory Information Service
|
|
86
100
|
this.registerCharacteristic({
|
|
87
101
|
characteristicType: Characteristic.Manufacturer,
|
package/lib/co-alarm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
export class CoAlarm extends BaseDeviceAccessory {
|
|
4
4
|
device;
|
|
5
5
|
accessory;
|
package/lib/contact-sensor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
export class ContactSensor extends BaseDeviceAccessory {
|
|
4
4
|
device;
|
|
5
5
|
accessory;
|
package/lib/fan.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class Fan extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
|
4
4
|
import { logInfo } from 'ring-client-api/util';
|
|
5
5
|
export class FloodFreezeSensor extends BaseDeviceAccessory {
|
package/lib/freeze-sensor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
|
4
4
|
import { logInfo } from 'ring-client-api/util';
|
|
5
5
|
export class FreezeSensor extends BaseDeviceAccessory {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { HomebridgePluginUiServer, RequestError, } from '@homebridge/plugin-ui-utils';
|
|
3
|
-
import { RingRestClient } from 'ring-client-api/rest-client';
|
|
4
|
-
import { controlCenterDisplayName, getSystemId } from
|
|
3
|
+
import { InvalidAuthResponseError, RingRestClient, } from 'ring-client-api/rest-client';
|
|
4
|
+
import { controlCenterDisplayName, getSystemId } from '../config.js';
|
|
5
5
|
class PluginUiServer extends HomebridgePluginUiServer {
|
|
6
6
|
restClient;
|
|
7
7
|
constructor() {
|
|
@@ -36,12 +36,16 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
36
36
|
generateToken = async ({ email, password, code }) => {
|
|
37
37
|
// use the existing restClient to avoid sending a token again
|
|
38
38
|
this.restClient = this.restClient || new RingRestClient({ email, password });
|
|
39
|
-
console.log(`Getting token for ${email}
|
|
39
|
+
console.log(`Getting token for ${email}`);
|
|
40
40
|
try {
|
|
41
41
|
const authResponse = await this.restClient.getAuth(code);
|
|
42
42
|
return { refreshToken: authResponse.refresh_token };
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
|
+
if (e instanceof InvalidAuthResponseError) {
|
|
46
|
+
console.error(e);
|
|
47
|
+
throw new RequestError(e.message, e);
|
|
48
|
+
}
|
|
45
49
|
console.error('Incorrect 2fa Code');
|
|
46
50
|
throw new RequestError('Please check the code and try again', e);
|
|
47
51
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { platformName, pluginName, RingPlatform } from
|
|
2
|
-
import { setHap } from
|
|
1
|
+
import { platformName, pluginName, RingPlatform } from './ring-platform.js';
|
|
2
|
+
import { setHap } from './hap.js';
|
|
3
3
|
export default function (homebridge) {
|
|
4
4
|
setHap(homebridge.hap);
|
|
5
5
|
homebridge.registerPlatform(pluginName, platformName, RingPlatform, true);
|
package/lib/intercom.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { hap } from
|
|
2
|
-
import { BaseDataAccessory } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
|
+
import { BaseDataAccessory } from './base-data-accessory.js';
|
|
3
3
|
import { logError, logInfo } from 'ring-client-api/util';
|
|
4
4
|
import { map, throttleTime } from 'rxjs/operators';
|
|
5
5
|
export class Intercom extends BaseDataAccessory {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { distinctUntilChanged } from 'rxjs/operators';
|
|
2
|
-
import { hap } from
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logError, logInfo } from 'ring-client-api/util';
|
|
4
|
-
import { BaseAccessory } from
|
|
4
|
+
import { BaseAccessory } from './base-accessory.js';
|
|
5
5
|
import { firstValueFrom, of } from 'rxjs';
|
|
6
6
|
function getStateFromMode(mode) {
|
|
7
7
|
const { Characteristic: { SecuritySystemCurrentState: State }, } = hap;
|
|
@@ -18,6 +18,7 @@ function getStateFromMode(mode) {
|
|
|
18
18
|
}
|
|
19
19
|
export class LocationModeSwitch extends BaseAccessory {
|
|
20
20
|
targetState;
|
|
21
|
+
modeRequestId = 0;
|
|
21
22
|
device;
|
|
22
23
|
location;
|
|
23
24
|
accessory;
|
|
@@ -36,7 +37,7 @@ export class LocationModeSwitch extends BaseAccessory {
|
|
|
36
37
|
if (state === this.targetState) {
|
|
37
38
|
this.targetState = undefined;
|
|
38
39
|
}
|
|
39
|
-
if (
|
|
40
|
+
if (this.targetState === undefined) {
|
|
40
41
|
targetState.updateValue(state);
|
|
41
42
|
}
|
|
42
43
|
currentState.updateValue(state);
|
|
@@ -58,28 +59,53 @@ export class LocationModeSwitch extends BaseAccessory {
|
|
|
58
59
|
: await getCurrentState());
|
|
59
60
|
});
|
|
60
61
|
targetState.on("set" /* CharacteristicEventTypes.SET */, async (state, callback) => {
|
|
61
|
-
const { Characteristic: { SecuritySystemTargetState: State }, } = hap;
|
|
62
|
+
const { Characteristic: { SecuritySystemTargetState: State }, } = hap, requestId = ++this.modeRequestId;
|
|
62
63
|
callback();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
try {
|
|
65
|
+
const current = await getCurrentState();
|
|
66
|
+
if (requestId !== this.modeRequestId) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (state === State.NIGHT_ARM) {
|
|
70
|
+
state = State.STAY_ARM;
|
|
71
|
+
// Ring doesn't have night mode, so switch over to stay mode
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
if (requestId === this.modeRequestId) {
|
|
74
|
+
targetState.updateValue(state);
|
|
75
|
+
}
|
|
76
|
+
}, 100);
|
|
77
|
+
}
|
|
78
|
+
if (state === current) {
|
|
79
|
+
this.targetState = undefined;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.targetState = state;
|
|
83
|
+
if (state === State.AWAY_ARM) {
|
|
84
|
+
logInfo(`Setting ${this.location.name} Mode to away`);
|
|
85
|
+
await this.location.setLocationMode('away');
|
|
86
|
+
}
|
|
87
|
+
else if (state === State.DISARM) {
|
|
88
|
+
logInfo(`Setting ${this.location.name} Mode to disarmed`);
|
|
89
|
+
await this.location.setLocationMode('disarmed');
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
logInfo(`Setting ${this.location.name} Mode to home`);
|
|
93
|
+
await this.location.setLocationMode('home');
|
|
94
|
+
}
|
|
67
95
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
catch (e) {
|
|
97
|
+
logError('Failed to set location mode for ' + location.name);
|
|
98
|
+
logError(e);
|
|
99
|
+
if (requestId !== this.modeRequestId) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const current = await getCurrentState();
|
|
103
|
+
if (requestId === this.modeRequestId) {
|
|
104
|
+
this.targetState = undefined;
|
|
105
|
+
this.modeRequestId++;
|
|
106
|
+
targetState.updateValue(current);
|
|
107
|
+
}
|
|
80
108
|
}
|
|
81
|
-
logInfo(`Setting ${this.location.name} Mode to home`);
|
|
82
|
-
return this.location.setLocationMode('home');
|
|
83
109
|
});
|
|
84
110
|
targetState.setProps({
|
|
85
111
|
validValues: [
|
package/lib/lock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
2
|
import { distinctUntilChanged } from 'rxjs/operators';
|
|
3
|
-
import { hap } from
|
|
3
|
+
import { hap } from './hap.js';
|
|
4
4
|
function getCurrentState({ locked }) {
|
|
5
5
|
const { Characteristic: { LockCurrentState: State }, } = hap;
|
|
6
6
|
switch (locked) {
|
package/lib/motion-sensor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
export class MotionSensor extends BaseDeviceAccessory {
|
|
4
4
|
device;
|
|
5
5
|
accessory;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class MultiLevelSwitch extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
package/lib/outlet.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class Outlet extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
package/lib/panic-buttons.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { hap } from
|
|
2
|
-
import { BaseDataAccessory } from
|
|
1
|
+
import { hap } from './hap.js';
|
|
2
|
+
import { BaseDataAccessory } from './base-data-accessory.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
const burglarStates = [
|
|
5
5
|
'burglar-alarm',
|
package/lib/ring-platform.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { RingApi, RingCamera, RingChime, RingDevice, RingDeviceCategory, RingDeviceType, RingIntercom, } from 'ring-client-api';
|
|
2
|
-
import { hap } from
|
|
3
|
-
import { SecurityPanel } from
|
|
4
|
-
import { Chime } from
|
|
5
|
-
import { BrightnessOnly } from
|
|
6
|
-
import { ContactSensor } from
|
|
7
|
-
import { MotionSensor } from
|
|
8
|
-
import { Lock } from
|
|
9
|
-
import { SmokeAlarm } from
|
|
10
|
-
import { CoAlarm } from
|
|
11
|
-
import { SmokeCoListener } from
|
|
12
|
-
import { controlCenterDisplayName, debug, getSystemId, updateHomebridgeConfig, } from
|
|
13
|
-
import { Beam } from
|
|
14
|
-
import { MultiLevelSwitch } from
|
|
15
|
-
import { Fan } from
|
|
16
|
-
import { Outlet } from
|
|
17
|
-
import { Switch } from
|
|
18
|
-
import { Camera } from
|
|
19
|
-
import { PanicButtons } from
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
|
+
import { SecurityPanel } from './security-panel.js';
|
|
4
|
+
import { Chime } from './chime.js';
|
|
5
|
+
import { BrightnessOnly } from './brightness-only.js';
|
|
6
|
+
import { ContactSensor } from './contact-sensor.js';
|
|
7
|
+
import { MotionSensor } from './motion-sensor.js';
|
|
8
|
+
import { Lock } from './lock.js';
|
|
9
|
+
import { SmokeAlarm } from './smoke-alarm.js';
|
|
10
|
+
import { CoAlarm } from './co-alarm.js';
|
|
11
|
+
import { SmokeCoListener } from './smoke-co-listener.js';
|
|
12
|
+
import { controlCenterDisplayName, debug, getSystemId, updateHomebridgeConfig, } from './config.js';
|
|
13
|
+
import { Beam } from './beam.js';
|
|
14
|
+
import { MultiLevelSwitch } from './multi-level-switch.js';
|
|
15
|
+
import { Fan } from './fan.js';
|
|
16
|
+
import { Outlet } from './outlet.js';
|
|
17
|
+
import { Switch } from './switch.js';
|
|
18
|
+
import { Camera } from './camera.js';
|
|
19
|
+
import { PanicButtons } from './panic-buttons.js';
|
|
20
20
|
import { logInfo, useLogger } from 'ring-client-api/util';
|
|
21
|
-
import { FloodFreezeSensor } from
|
|
22
|
-
import { FreezeSensor } from
|
|
23
|
-
import { TemperatureSensor } from
|
|
24
|
-
import { WaterSensor } from
|
|
25
|
-
import { LocationModeSwitch } from
|
|
26
|
-
import { Thermostat } from
|
|
27
|
-
import { UnknownZWaveSwitchSwitch } from
|
|
28
|
-
import { Intercom } from
|
|
29
|
-
import { Valve } from
|
|
21
|
+
import { FloodFreezeSensor } from './flood-freeze-sensor.js';
|
|
22
|
+
import { FreezeSensor } from './freeze-sensor.js';
|
|
23
|
+
import { TemperatureSensor } from './temperature-sensor.js';
|
|
24
|
+
import { WaterSensor } from './water-sensor.js';
|
|
25
|
+
import { LocationModeSwitch } from './location-mode-switch.js';
|
|
26
|
+
import { Thermostat } from './thermostat.js';
|
|
27
|
+
import { UnknownZWaveSwitchSwitch } from './unknown-zwave-switch.js';
|
|
28
|
+
import { Intercom } from './intercom.js';
|
|
29
|
+
import { Valve } from './valve.js';
|
|
30
30
|
const ignoreHiddenDeviceTypes = [
|
|
31
31
|
RingDeviceType.RingNetAdapter,
|
|
32
32
|
RingDeviceType.ZigbeeAdapter,
|
|
@@ -39,7 +39,7 @@ const ignoreHiddenDeviceTypes = [
|
|
|
39
39
|
];
|
|
40
40
|
export const platformName = 'Ring';
|
|
41
41
|
export const pluginName = 'homebridge-ring';
|
|
42
|
-
function getAccessoryClass(device) {
|
|
42
|
+
export function getAccessoryClass(device) {
|
|
43
43
|
const { deviceType } = device;
|
|
44
44
|
if (device.data.status === 'disabled') {
|
|
45
45
|
return null;
|
|
@@ -67,6 +67,7 @@ function getAccessoryClass(device) {
|
|
|
67
67
|
case RingDeviceType.CoAlarm:
|
|
68
68
|
return CoAlarm;
|
|
69
69
|
case RingDeviceType.SmokeCoListener:
|
|
70
|
+
case RingDeviceType.KiddeSmokeCoAlarm:
|
|
70
71
|
return SmokeCoListener;
|
|
71
72
|
case RingDeviceType.BeamsMotionSensor:
|
|
72
73
|
case RingDeviceType.BeamsSwitch:
|
|
@@ -228,8 +229,7 @@ export class RingPlatform {
|
|
|
228
229
|
}
|
|
229
230
|
const createHomebridgeAccessory = () => {
|
|
230
231
|
const accessory = new api.platformAccessory(displayName, uuid, isCamera
|
|
231
|
-
? 17 /* hap.Categories.CAMERA */
|
|
232
|
-
: 11 /* hap.Categories.SECURITY_SYSTEM */);
|
|
232
|
+
? 17 /* hap.Categories.CAMERA */ : 11 /* hap.Categories.SECURITY_SYSTEM */);
|
|
233
233
|
if (isCamera) {
|
|
234
234
|
logInfo(`Configured camera ${uuid} ${deviceType} ${displayName}`);
|
|
235
235
|
externalAccessories.push(accessory);
|
package/lib/security-panel.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
2
|
import { allAlarmStates, RingDeviceType } from 'ring-client-api';
|
|
3
|
-
import { hap } from
|
|
3
|
+
import { hap } from './hap.js';
|
|
4
4
|
import { logError, logInfo } from 'ring-client-api/util';
|
|
5
5
|
function isValidNightModeBypass(mode) {
|
|
6
6
|
return mode && (mode === 'all' || mode === 'some');
|
|
@@ -45,7 +45,7 @@ export class SecurityPanel extends BaseDeviceAccessory {
|
|
|
45
45
|
characteristicType: Characteristic.On,
|
|
46
46
|
serviceType: Service.Switch,
|
|
47
47
|
name: this.device.name + ' Siren',
|
|
48
|
-
getValue: (data) => data.siren && data.siren.state === 'on',
|
|
48
|
+
getValue: (data) => Boolean(data.siren && data.siren.state === 'on'),
|
|
49
49
|
setValue: (value) => {
|
|
50
50
|
if (value) {
|
|
51
51
|
return this.device.location.soundSiren();
|
package/lib/smoke-alarm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
export class SmokeAlarm extends BaseDeviceAccessory {
|
|
4
4
|
device;
|
|
5
5
|
accessory;
|
package/lib/smoke-co-listener.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
export class SmokeCoListener extends BaseDeviceAccessory {
|
|
4
4
|
device;
|
|
5
5
|
accessory;
|
|
@@ -14,7 +14,9 @@ export class SmokeCoListener extends BaseDeviceAccessory {
|
|
|
14
14
|
characteristicType: SmokeDetected,
|
|
15
15
|
serviceType: SmokeSensor,
|
|
16
16
|
getValue: (data) => {
|
|
17
|
-
|
|
17
|
+
const smokeAlarmStatus = data.smoke?.alarmStatus ??
|
|
18
|
+
data.components?.['alarm.smoke']?.alarmStatus;
|
|
19
|
+
return smokeAlarmStatus === 'active'
|
|
18
20
|
? SmokeDetected.SMOKE_DETECTED
|
|
19
21
|
: SmokeDetected.SMOKE_NOT_DETECTED;
|
|
20
22
|
},
|
|
@@ -23,7 +25,8 @@ export class SmokeCoListener extends BaseDeviceAccessory {
|
|
|
23
25
|
characteristicType: CarbonMonoxideDetected,
|
|
24
26
|
serviceType: CarbonMonoxideSensor,
|
|
25
27
|
getValue: (data) => {
|
|
26
|
-
|
|
28
|
+
const coAlarmStatus = data.co?.alarmStatus ?? data.components?.['alarm.co']?.alarmStatus;
|
|
29
|
+
return coAlarmStatus === 'active'
|
|
27
30
|
? CarbonMonoxideDetected.CO_LEVELS_ABNORMAL
|
|
28
31
|
: CarbonMonoxideDetected.CO_LEVELS_NORMAL;
|
|
29
32
|
},
|
package/lib/switch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class Switch extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
|
4
4
|
export class TemperatureSensor extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
package/lib/thermostat.js
CHANGED
|
@@ -2,8 +2,8 @@ import { combineLatest } from 'rxjs';
|
|
|
2
2
|
import { distinctUntilChanged, map, switchMap } from 'rxjs/operators';
|
|
3
3
|
import { RingDeviceType } from 'ring-client-api';
|
|
4
4
|
import { logDebug, logError, logInfo } from 'ring-client-api/util';
|
|
5
|
-
import { BaseDeviceAccessory } from
|
|
6
|
-
import { hap } from
|
|
5
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
6
|
+
import { hap } from './hap.js';
|
|
7
7
|
export class Thermostat extends BaseDeviceAccessory {
|
|
8
8
|
onTemperature;
|
|
9
9
|
device;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class UnknownZWaveSwitchSwitch extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
package/lib/valve.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { logInfo } from 'ring-client-api/util';
|
|
4
4
|
export class Valve extends BaseDeviceAccessory {
|
|
5
5
|
device;
|
package/lib/water-sensor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseDeviceAccessory } from
|
|
2
|
-
import { hap } from
|
|
1
|
+
import { BaseDeviceAccessory } from './base-device-accessory.js';
|
|
2
|
+
import { hap } from './hap.js';
|
|
3
3
|
import { distinctUntilChanged, filter, map } from 'rxjs/operators';
|
|
4
4
|
import { logInfo } from 'ring-client-api/util';
|
|
5
5
|
export class WaterSensor extends BaseDeviceAccessory {
|
package/package.json
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-ring",
|
|
3
3
|
"displayName": "Ring",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "15.0.0-beta.0",
|
|
5
5
|
"description": "Homebridge plugin for Ring doorbells, cameras, security alarm system and smart lighting",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "rm -rf lib && tsc && cp -r ./homebridge-ui/public ./lib/homebridge-ui/public/",
|
|
9
|
+
"build": "rm -rf lib && tsc && cp -r ./homebridge-ui/public ./lib/homebridge-ui/public/ && rm -rf ./lib/test",
|
|
10
10
|
"lint": "eslint .",
|
|
11
|
-
"
|
|
12
|
-
"dev
|
|
13
|
-
"dev:run": "
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"dev": "bash ./dev-homebridge.sh",
|
|
13
|
+
"dev:run": "npm run dev"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@homebridge/camera-utils": "^3.0.0",
|
|
17
|
-
"@homebridge/plugin-ui-utils": "^2.
|
|
18
|
-
"ring-client-api": "
|
|
19
|
-
"werift": "0.
|
|
17
|
+
"@homebridge/plugin-ui-utils": "^2.2.7",
|
|
18
|
+
"ring-client-api": "15.0.0-beta.0",
|
|
19
|
+
"werift": "0.26.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"
|
|
22
|
+
"@homebridge/hap-nodejs": "^2.3.0",
|
|
23
23
|
"eslint-config-shared": "*",
|
|
24
|
-
"homebridge": "
|
|
24
|
+
"homebridge": "2.5.0",
|
|
25
25
|
"tsconfig": "*",
|
|
26
|
-
"typescript": "
|
|
26
|
+
"typescript": "7.0.2",
|
|
27
|
+
"vitest": "^5.1.0"
|
|
27
28
|
},
|
|
28
29
|
"engines": {
|
|
29
|
-
"node": "^
|
|
30
|
+
"node": "^22.19.0 || ^24 || ^26",
|
|
30
31
|
"homebridge": ">=1.4.0 || ^2.0.0-beta.0"
|
|
31
32
|
},
|
|
32
33
|
"repository": {
|