ring-client-api 13.2.1 → 14.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/lib/api.d.ts +9 -7
- package/lib/api.js +56 -63
- package/lib/device-data.js +6 -9
- package/lib/ffmpeg.js +2 -6
- package/lib/index.d.ts +7 -7
- package/lib/index.js +7 -23
- package/lib/location.d.ts +22 -21
- package/lib/location.js +61 -65
- package/lib/refresh-token.js +6 -10
- package/lib/rest-client.d.ts +3 -3
- package/lib/rest-client.js +39 -50
- package/lib/ring-auth-cli.js +2 -4
- package/lib/ring-camera.d.ts +21 -18
- package/lib/ring-camera.js +57 -56
- package/lib/ring-chime.d.ts +5 -5
- package/lib/ring-chime.js +10 -14
- package/lib/ring-device-data-cli.js +2 -4
- package/lib/ring-device.d.ts +4 -4
- package/lib/ring-device.js +12 -16
- package/lib/ring-intercom.d.ts +6 -6
- package/lib/ring-intercom.js +19 -23
- package/lib/ring-types.d.ts +2 -0
- package/lib/ring-types.js +24 -24
- package/lib/streaming/peer-connection.d.ts +5 -3
- package/lib/streaming/peer-connection.js +25 -30
- package/lib/streaming/simple-webrtc-session.d.ts +2 -2
- package/lib/streaming/simple-webrtc-session.js +3 -7
- package/lib/streaming/streaming-messages.js +1 -2
- package/lib/streaming/streaming-session.d.ts +3 -3
- package/lib/streaming/streaming-session.js +34 -38
- package/lib/streaming/webrtc-connection.d.ts +4 -4
- package/lib/streaming/webrtc-connection.js +38 -42
- package/lib/subscribed.d.ts +1 -1
- package/lib/subscribed.js +1 -5
- package/lib/util.js +33 -54
- package/package.json +14 -16
- package/lib/test/rest-client.spec.d.ts +0 -1
- package/lib/test/rest-client.spec.js +0 -242
- package/lib/test/ring-camera.spec.d.ts +0 -1
- package/lib/test/ring-camera.spec.js +0 -37
package/lib/ring-camera.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { RingCameraKind } from './ring-types.ts';
|
|
2
|
+
import { type CameraData, type CameraDeviceSettingsData, type CameraEventOptions, type CameraEventResponse, type CameraHealth, type HistoryOptions, type PeriodicFootageResponse, type PushNotificationDingV2, type VideoSearchResponse, type OnvifCameraData, type PushNotification } from './ring-types.ts';
|
|
3
|
+
import type { RingRestClient } from './rest-client.ts';
|
|
3
4
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
|
-
import { DeepPartial } from './util';
|
|
5
|
-
import { Subscribed } from './subscribed';
|
|
6
|
-
import { StreamingConnectionOptions } from './streaming/webrtc-connection';
|
|
7
|
-
import { FfmpegOptions
|
|
8
|
-
import {
|
|
5
|
+
import { type DeepPartial } from './util.ts';
|
|
6
|
+
import { Subscribed } from './subscribed.ts';
|
|
7
|
+
import type { StreamingConnectionOptions } from './streaming/webrtc-connection.ts';
|
|
8
|
+
import type { FfmpegOptions } from './streaming/streaming-session.ts';
|
|
9
|
+
import { StreamingSession } from './streaming/streaming-session.ts';
|
|
10
|
+
import { SimpleWebRtcSession } from './streaming/simple-webrtc-session.ts';
|
|
9
11
|
export type AnyCameraData = CameraData | OnvifCameraData;
|
|
10
12
|
export declare function getBatteryLevel(data: Pick<CameraData, 'battery_life' | 'battery_life_2'> & {
|
|
11
13
|
health?: Partial<CameraData['health']>;
|
|
@@ -46,6 +48,7 @@ export declare class RingCamera extends Subscribed {
|
|
|
46
48
|
get hasLowBattery(): boolean;
|
|
47
49
|
get isCharging(): boolean;
|
|
48
50
|
get operatingOnBattery(): boolean;
|
|
51
|
+
get canTakeSnapshotWhileRecording(): boolean;
|
|
49
52
|
get isOffline(): boolean;
|
|
50
53
|
get isRingEdgeEnabled(): boolean;
|
|
51
54
|
get hasInHomeDoorbell(): boolean;
|
|
@@ -54,24 +57,24 @@ export declare class RingCamera extends Subscribed {
|
|
|
54
57
|
setLight(on: boolean): Promise<boolean>;
|
|
55
58
|
setSiren(on: boolean): Promise<boolean>;
|
|
56
59
|
setSettings(settings: DeepPartial<CameraData['settings']>): Promise<void>;
|
|
57
|
-
setDeviceSettings(settings: DeepPartial<CameraDeviceSettingsData>): Promise<CameraDeviceSettingsData & import("./rest-client").ExtendedResponse>;
|
|
58
|
-
getDeviceSettings(): Promise<CameraDeviceSettingsData & import("./rest-client").ExtendedResponse>;
|
|
60
|
+
setDeviceSettings(settings: DeepPartial<CameraDeviceSettingsData>): Promise<CameraDeviceSettingsData & import("./rest-client.ts").ExtendedResponse>;
|
|
61
|
+
getDeviceSettings(): Promise<CameraDeviceSettingsData & import("./rest-client.ts").ExtendedResponse>;
|
|
59
62
|
setInHomeDoorbell(enable: boolean): Promise<boolean>;
|
|
60
63
|
getHealth(): Promise<CameraHealth>;
|
|
61
64
|
private createStreamingConnection;
|
|
62
65
|
startLiveCall(options?: StreamingConnectionOptions): Promise<StreamingSession>;
|
|
63
66
|
private removeDingById;
|
|
64
67
|
processPushNotification(notification: PushNotification): void;
|
|
65
|
-
getEvents(options?: CameraEventOptions): Promise<CameraEventResponse & import("./rest-client").ExtendedResponse>;
|
|
68
|
+
getEvents(options?: CameraEventOptions): Promise<CameraEventResponse & import("./rest-client.ts").ExtendedResponse>;
|
|
66
69
|
videoSearch({ dateFrom, dateTo, order }?: {
|
|
67
70
|
dateFrom: number;
|
|
68
71
|
dateTo: number;
|
|
69
72
|
order?: string | undefined;
|
|
70
|
-
}): Promise<VideoSearchResponse & import("./rest-client").ExtendedResponse>;
|
|
73
|
+
}): Promise<VideoSearchResponse & import("./rest-client.ts").ExtendedResponse>;
|
|
71
74
|
getPeriodicalFootage({ startAtMs, endAtMs }?: {
|
|
72
75
|
startAtMs: number;
|
|
73
76
|
endAtMs: number;
|
|
74
|
-
}): Promise<PeriodicFootageResponse & import("./rest-client").ExtendedResponse>;
|
|
77
|
+
}): Promise<PeriodicFootageResponse & import("./rest-client.ts").ExtendedResponse>;
|
|
75
78
|
getRecordingUrl(dingIdStr: string, { transcoded }?: {
|
|
76
79
|
transcoded?: boolean | undefined;
|
|
77
80
|
}): Promise<string>;
|
|
@@ -94,8 +97,8 @@ export declare class RingCamera extends Subscribed {
|
|
|
94
97
|
maxWaitMs?: number;
|
|
95
98
|
force?: boolean;
|
|
96
99
|
uuid?: string;
|
|
97
|
-
}): Promise<Buffer<ArrayBufferLike> & import("./rest-client").ExtendedResponse>;
|
|
98
|
-
getSnapshotByUuid(uuid: string): Promise<Buffer<ArrayBufferLike> & import("./rest-client").ExtendedResponse>;
|
|
100
|
+
}): Promise<Buffer<ArrayBufferLike> & import("./rest-client.ts").ExtendedResponse>;
|
|
101
|
+
getSnapshotByUuid(uuid: string): Promise<Buffer<ArrayBufferLike> & import("./rest-client.ts").ExtendedResponse>;
|
|
99
102
|
recordToFile(outputPath: string, duration?: number): Promise<void>;
|
|
100
103
|
streamVideo(ffmpegOptions: FfmpegOptions): Promise<StreamingSession>;
|
|
101
104
|
/**
|
|
@@ -105,9 +108,9 @@ export declare class RingCamera extends Subscribed {
|
|
|
105
108
|
* enabled as soon as the stream starts, which can drain the battery more quickly.
|
|
106
109
|
*/
|
|
107
110
|
createSimpleWebRtcSession(): SimpleWebRtcSession;
|
|
108
|
-
subscribeToDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
109
|
-
unsubscribeFromDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
110
|
-
subscribeToMotionEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
111
|
-
unsubscribeFromMotionEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
111
|
+
subscribeToDingEvents(): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
112
|
+
unsubscribeFromDingEvents(): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
113
|
+
subscribeToMotionEvents(): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
114
|
+
unsubscribeFromMotionEvents(): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
112
115
|
disconnect(): void;
|
|
113
116
|
}
|
package/lib/ring-camera.js
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const util_1 = require("./util");
|
|
12
|
-
const subscribed_1 = require("./subscribed");
|
|
13
|
-
const webrtc_connection_1 = require("./streaming/webrtc-connection");
|
|
14
|
-
const streaming_session_1 = require("./streaming/streaming-session");
|
|
15
|
-
const simple_webrtc_session_1 = require("./streaming/simple-webrtc-session");
|
|
1
|
+
import { RingCameraKind } from "./ring-types.js";
|
|
2
|
+
import { DoorbellType, PushNotificationAction, RingCameraModel, } from "./ring-types.js";
|
|
3
|
+
import { appApi, clientApi, deviceApi } from "./rest-client.js";
|
|
4
|
+
import { BehaviorSubject, firstValueFrom, ReplaySubject, Subject } from 'rxjs';
|
|
5
|
+
import { distinctUntilChanged, filter, map, share, startWith, throttleTime, } from 'rxjs/operators';
|
|
6
|
+
import { buildSearchString, delay, logDebug, logError, } from "./util.js";
|
|
7
|
+
import { Subscribed } from "./subscribed.js";
|
|
8
|
+
import { WebrtcConnection } from "./streaming/webrtc-connection.js";
|
|
9
|
+
import { StreamingSession } from "./streaming/streaming-session.js";
|
|
10
|
+
import { SimpleWebRtcSession } from "./streaming/simple-webrtc-session.js";
|
|
16
11
|
const maxSnapshotRefreshSeconds = 15, fullDayMs = 24 * 60 * 60 * 1000;
|
|
17
12
|
function parseBatteryLife(batteryLife) {
|
|
18
13
|
if (batteryLife === null || batteryLife === undefined) {
|
|
@@ -32,7 +27,7 @@ function getStartOfToday() {
|
|
|
32
27
|
function getEndOfToday() {
|
|
33
28
|
return getStartOfToday() + fullDayMs - 1;
|
|
34
29
|
}
|
|
35
|
-
function getBatteryLevel(data) {
|
|
30
|
+
export function getBatteryLevel(data) {
|
|
36
31
|
const levels = [
|
|
37
32
|
parseBatteryLife(data.battery_life),
|
|
38
33
|
parseBatteryLife(data.battery_life_2),
|
|
@@ -46,7 +41,7 @@ function getBatteryLevel(data) {
|
|
|
46
41
|
}
|
|
47
42
|
return Math.min(...levels);
|
|
48
43
|
}
|
|
49
|
-
function getSearchQueryString(options) {
|
|
44
|
+
export function getSearchQueryString(options) {
|
|
50
45
|
const queryString = Object.entries(options)
|
|
51
46
|
.map(([key, value]) => {
|
|
52
47
|
if (value === undefined) {
|
|
@@ -61,13 +56,16 @@ function getSearchQueryString(options) {
|
|
|
61
56
|
.join('&');
|
|
62
57
|
return queryString.length ? `?${queryString}` : '';
|
|
63
58
|
}
|
|
64
|
-
function cleanSnapshotUuid(uuid) {
|
|
59
|
+
export function cleanSnapshotUuid(uuid) {
|
|
65
60
|
if (!uuid) {
|
|
66
61
|
return uuid;
|
|
67
62
|
}
|
|
68
63
|
return uuid.replace(/:.*$/, '');
|
|
69
64
|
}
|
|
70
|
-
|
|
65
|
+
const wiredModelsWithNoSnapshotDuringRecording = new Set([
|
|
66
|
+
RingCameraKind.doorbell_graham_cracker,
|
|
67
|
+
]);
|
|
68
|
+
export class RingCamera extends Subscribed {
|
|
71
69
|
initialData;
|
|
72
70
|
isDoorbot;
|
|
73
71
|
restClient;
|
|
@@ -78,19 +76,19 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
78
76
|
onData;
|
|
79
77
|
hasLight;
|
|
80
78
|
hasSiren;
|
|
81
|
-
onRequestUpdate = new
|
|
82
|
-
onNewNotification = new
|
|
83
|
-
onActiveNotifications = new
|
|
84
|
-
onDoorbellPressed = this.onNewNotification.pipe(
|
|
85
|
-
onMotionDetected = this.onActiveNotifications.pipe(
|
|
86
|
-
|
|
87
|
-
connector: () => new
|
|
79
|
+
onRequestUpdate = new Subject();
|
|
80
|
+
onNewNotification = new Subject();
|
|
81
|
+
onActiveNotifications = new BehaviorSubject([]);
|
|
82
|
+
onDoorbellPressed = this.onNewNotification.pipe(filter((notification) => notification.android_config.category === PushNotificationAction.Ding), share());
|
|
83
|
+
onMotionDetected = this.onActiveNotifications.pipe(map((notifications) => notifications.some((notification) => notification.android_config.category ===
|
|
84
|
+
PushNotificationAction.Motion)), distinctUntilChanged(), share({
|
|
85
|
+
connector: () => new ReplaySubject(1),
|
|
88
86
|
resetOnError: false,
|
|
89
87
|
resetOnComplete: false,
|
|
90
88
|
resetOnRefCountZero: false,
|
|
91
89
|
}));
|
|
92
|
-
onMotionStarted = this.onMotionDetected.pipe(
|
|
93
|
-
|
|
90
|
+
onMotionStarted = this.onMotionDetected.pipe(filter((currentlyDetected) => currentlyDetected), map(() => null), // no value needed, event is what matters
|
|
91
|
+
share());
|
|
94
92
|
onBatteryLevel;
|
|
95
93
|
onInHomeDoorbellStatus;
|
|
96
94
|
constructor(initialData, isDoorbot, restClient, avoidSnapshotBatteryDrain) {
|
|
@@ -102,34 +100,34 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
102
100
|
this.id = this.initialData.id;
|
|
103
101
|
this.deviceType = this.initialData.kind;
|
|
104
102
|
this.model =
|
|
105
|
-
|
|
103
|
+
RingCameraModel[this.initialData.kind] ||
|
|
106
104
|
'Unknown Model';
|
|
107
|
-
this.onData = new
|
|
105
|
+
this.onData = new BehaviorSubject(this.initialData);
|
|
108
106
|
this.hasLight = this.initialData.led_status !== undefined;
|
|
109
107
|
this.hasSiren = this.initialData.siren_status !== undefined;
|
|
110
|
-
this.onBatteryLevel = this.onData.pipe(
|
|
108
|
+
this.onBatteryLevel = this.onData.pipe(map((data) => {
|
|
111
109
|
if (!('battery_life' in data)) {
|
|
112
110
|
return null;
|
|
113
111
|
}
|
|
114
112
|
return getBatteryLevel(data);
|
|
115
|
-
}),
|
|
116
|
-
this.onInHomeDoorbellStatus = this.onData.pipe(
|
|
113
|
+
}), distinctUntilChanged());
|
|
114
|
+
this.onInHomeDoorbellStatus = this.onData.pipe(map(({ settings: { chime_settings } }) => {
|
|
117
115
|
return Boolean(chime_settings?.enable);
|
|
118
|
-
}),
|
|
116
|
+
}), distinctUntilChanged());
|
|
119
117
|
this.addSubscriptions(this.restClient.onSession
|
|
120
|
-
.pipe(
|
|
118
|
+
.pipe(startWith(undefined), throttleTime(1000)) // Force this to run immediately, but don't double run if a session is created due to these api calls
|
|
121
119
|
.subscribe(() => {
|
|
122
120
|
this.subscribeToDingEvents().catch((e) => {
|
|
123
|
-
|
|
121
|
+
logError('Failed to subscribe ' +
|
|
124
122
|
initialData.description +
|
|
125
123
|
' to ding events');
|
|
126
|
-
|
|
124
|
+
logError(e);
|
|
127
125
|
});
|
|
128
126
|
this.subscribeToMotionEvents().catch((e) => {
|
|
129
|
-
|
|
127
|
+
logError('Failed to subscribe ' +
|
|
130
128
|
initialData.description +
|
|
131
129
|
' to motion events');
|
|
132
|
-
|
|
130
|
+
logError(e);
|
|
133
131
|
});
|
|
134
132
|
}));
|
|
135
133
|
}
|
|
@@ -177,6 +175,10 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
177
175
|
get operatingOnBattery() {
|
|
178
176
|
return this.hasBattery && this.data.settings.power_mode !== 'wired';
|
|
179
177
|
}
|
|
178
|
+
get canTakeSnapshotWhileRecording() {
|
|
179
|
+
return (!this.operatingOnBattery &&
|
|
180
|
+
!wiredModelsWithNoSnapshotDuringRecording.has(this.data.kind));
|
|
181
|
+
}
|
|
180
182
|
get isOffline() {
|
|
181
183
|
return this.data.alerts.connection === 'offline';
|
|
182
184
|
}
|
|
@@ -187,13 +189,13 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
187
189
|
const { chime_settings } = this.data.settings;
|
|
188
190
|
return (this.isDoorbot &&
|
|
189
191
|
Boolean(chime_settings &&
|
|
190
|
-
[
|
|
192
|
+
[DoorbellType.Mechanical, DoorbellType.Digital].includes(chime_settings.type)));
|
|
191
193
|
}
|
|
192
194
|
doorbotUrl(path = '') {
|
|
193
|
-
return
|
|
195
|
+
return clientApi(`doorbots/${this.id}/${path}`);
|
|
194
196
|
}
|
|
195
197
|
deviceUrl(path = '') {
|
|
196
|
-
return
|
|
198
|
+
return deviceApi(`devices/${this.id}/${path}`);
|
|
197
199
|
}
|
|
198
200
|
async setLight(on) {
|
|
199
201
|
if (!this.hasLight) {
|
|
@@ -263,16 +265,16 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
263
265
|
const response = await this.restClient
|
|
264
266
|
.request({
|
|
265
267
|
method: 'POST',
|
|
266
|
-
url:
|
|
268
|
+
url: appApi('clap/ticket/request/signalsocket'),
|
|
267
269
|
})
|
|
268
270
|
.catch((e) => {
|
|
269
271
|
throw e;
|
|
270
272
|
});
|
|
271
|
-
return new
|
|
273
|
+
return new WebrtcConnection(response.ticket, this, options);
|
|
272
274
|
}
|
|
273
275
|
async startLiveCall(options = {}) {
|
|
274
276
|
const connection = await this.createStreamingConnection(options);
|
|
275
|
-
return new
|
|
277
|
+
return new StreamingSession(this, connection);
|
|
276
278
|
}
|
|
277
279
|
removeDingById(idToRemove) {
|
|
278
280
|
const allActiveDings = this.activeNotifications, otherDings = allActiveDings.filter(({ data }) => data.event.ding.id !== idToRemove);
|
|
@@ -296,7 +298,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
296
298
|
}
|
|
297
299
|
getEvents(options = {}) {
|
|
298
300
|
return this.restClient.request({
|
|
299
|
-
url:
|
|
301
|
+
url: clientApi(`locations/${this.data.location_id}/devices/${this.id}/events${getSearchQueryString(options)}`),
|
|
300
302
|
});
|
|
301
303
|
}
|
|
302
304
|
videoSearch({ dateFrom, dateTo, order = 'asc' } = {
|
|
@@ -304,7 +306,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
304
306
|
dateTo: getEndOfToday(),
|
|
305
307
|
}) {
|
|
306
308
|
return this.restClient.request({
|
|
307
|
-
url:
|
|
309
|
+
url: clientApi(`video_search/history?doorbot_id=${this.id}&date_from=${dateFrom}&date_to=${dateTo}&order=${order}&api_version=11&includes%5B%5D=pva`),
|
|
308
310
|
});
|
|
309
311
|
}
|
|
310
312
|
getPeriodicalFootage({ startAtMs, endAtMs } = {
|
|
@@ -318,7 +320,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
318
320
|
}
|
|
319
321
|
async getRecordingUrl(dingIdStr, { transcoded = false } = {}) {
|
|
320
322
|
const path = transcoded ? 'recording' : 'share/play', response = await this.restClient.request({
|
|
321
|
-
url:
|
|
323
|
+
url: clientApi(`dings/${dingIdStr}/${path}?disable_redirect=true`),
|
|
322
324
|
});
|
|
323
325
|
return response.url;
|
|
324
326
|
}
|
|
@@ -355,7 +357,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
355
357
|
return true;
|
|
356
358
|
}
|
|
357
359
|
if (this.hasSnapshotWithinLifetime) {
|
|
358
|
-
|
|
360
|
+
logDebug(`Snapshot for ${this.name} is still within its life time (${this.currentTimestampAge / 1000}s old)`);
|
|
359
361
|
return true;
|
|
360
362
|
}
|
|
361
363
|
if (!this.avoidSnapshotBatteryDrain || !this.operatingOnBattery) {
|
|
@@ -377,8 +379,8 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
377
379
|
afterMs: this.lastSnapshotTimestamp,
|
|
378
380
|
force: true,
|
|
379
381
|
}),
|
|
380
|
-
|
|
381
|
-
const extraMessageForBatteryCam = this.
|
|
382
|
+
delay(maxSnapshotRefreshSeconds * 1000).then(() => {
|
|
383
|
+
const extraMessageForBatteryCam = !this.canTakeSnapshotWhileRecording
|
|
382
384
|
? '. This is normal behavior since this camera is unable to capture snapshots while streaming'
|
|
383
385
|
: '';
|
|
384
386
|
throw new Error(`Snapshot for ${this.name} (${this.deviceType} - ${this.model}) failed to refresh after ${maxSnapshotRefreshSeconds} seconds${extraMessageForBatteryCam}`);
|
|
@@ -397,7 +399,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
397
399
|
}
|
|
398
400
|
async getNextSnapshot({ afterMs, maxWaitMs, force, uuid, }) {
|
|
399
401
|
const response = await this.restClient.request({
|
|
400
|
-
url: `https://app-snaps.ring.com/snapshots/next/${this.id}${
|
|
402
|
+
url: `https://app-snaps.ring.com/snapshots/next/${this.id}${buildSearchString({
|
|
401
403
|
'after-ms': afterMs,
|
|
402
404
|
'max-wait-ms': maxWaitMs,
|
|
403
405
|
extras: force ? 'force' : undefined,
|
|
@@ -415,7 +417,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
415
417
|
}
|
|
416
418
|
getSnapshotByUuid(uuid) {
|
|
417
419
|
return this.restClient.request({
|
|
418
|
-
url:
|
|
420
|
+
url: clientApi('snapshots/uuid?uuid=' + cleanSnapshotUuid(uuid)),
|
|
419
421
|
responseType: 'buffer',
|
|
420
422
|
headers: {
|
|
421
423
|
accept: 'image/jpeg',
|
|
@@ -426,7 +428,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
426
428
|
const liveCall = await this.streamVideo({
|
|
427
429
|
output: ['-t', duration.toString(), outputPath],
|
|
428
430
|
});
|
|
429
|
-
await
|
|
431
|
+
await firstValueFrom(liveCall.onCallEnded);
|
|
430
432
|
}
|
|
431
433
|
async streamVideo(ffmpegOptions) {
|
|
432
434
|
const liveCall = await this.startLiveCall();
|
|
@@ -440,7 +442,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
440
442
|
* enabled as soon as the stream starts, which can drain the battery more quickly.
|
|
441
443
|
*/
|
|
442
444
|
createSimpleWebRtcSession() {
|
|
443
|
-
return new
|
|
445
|
+
return new SimpleWebRtcSession(this, this.restClient);
|
|
444
446
|
}
|
|
445
447
|
subscribeToDingEvents() {
|
|
446
448
|
return this.restClient.request({
|
|
@@ -470,4 +472,3 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
470
472
|
this.unsubscribe();
|
|
471
473
|
}
|
|
472
474
|
}
|
|
473
|
-
exports.RingCamera = RingCamera;
|
package/lib/ring-chime.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ChimeData, ChimeUpdate, ChimeSoundKind, RingtoneOptions, ChimeHealth } from './ring-types';
|
|
2
|
-
import { RingRestClient } from './rest-client';
|
|
1
|
+
import type { ChimeData, ChimeUpdate, ChimeSoundKind, RingtoneOptions, ChimeHealth } from './ring-types.ts';
|
|
2
|
+
import type { RingRestClient } from './rest-client.ts';
|
|
3
3
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
4
|
export declare class RingChime {
|
|
5
5
|
private initialData;
|
|
6
6
|
private restClient;
|
|
7
7
|
id: number;
|
|
8
|
-
deviceType: import("./ring-types").ChimeKind;
|
|
8
|
+
deviceType: import("./ring-types.ts").ChimeKind;
|
|
9
9
|
model: string;
|
|
10
10
|
onData: BehaviorSubject<ChimeData>;
|
|
11
11
|
onRequestUpdate: Subject<unknown>;
|
|
@@ -16,7 +16,7 @@ export declare class RingChime {
|
|
|
16
16
|
get name(): string;
|
|
17
17
|
get description(): string;
|
|
18
18
|
get volume(): number;
|
|
19
|
-
getRingtones(): Promise<RingtoneOptions & import("./rest-client").ExtendedResponse>;
|
|
19
|
+
getRingtones(): Promise<RingtoneOptions & import("./rest-client.ts").ExtendedResponse>;
|
|
20
20
|
getRingtoneByDescription(description: string, kind: ChimeSoundKind): Promise<{
|
|
21
21
|
user_id: string;
|
|
22
22
|
id: string;
|
|
@@ -27,7 +27,7 @@ export declare class RingChime {
|
|
|
27
27
|
available: string;
|
|
28
28
|
}>;
|
|
29
29
|
chimeUrl(path?: string): string;
|
|
30
|
-
playSound(kind: ChimeSoundKind): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
30
|
+
playSound(kind: ChimeSoundKind): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
31
31
|
snooze(time: number): Promise<void>;
|
|
32
32
|
clearSnooze(): Promise<void>;
|
|
33
33
|
updateChime(update: ChimeUpdate): Promise<boolean>;
|
package/lib/ring-chime.js
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const ring_types_1 = require("./ring-types");
|
|
5
|
-
const rest_client_1 = require("./rest-client");
|
|
6
|
-
const rxjs_1 = require("rxjs");
|
|
1
|
+
import { ChimeModel } from "./ring-types.js";
|
|
2
|
+
import { clientApi } from "./rest-client.js";
|
|
3
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
7
4
|
const settingsWhichRequireReboot = [
|
|
8
5
|
'ding_audio_id',
|
|
9
6
|
'ding_audio_user_id',
|
|
10
7
|
'motion_audio_id',
|
|
11
8
|
'motion_audio_user_id',
|
|
12
9
|
];
|
|
13
|
-
class RingChime {
|
|
10
|
+
export class RingChime {
|
|
14
11
|
initialData;
|
|
15
12
|
restClient;
|
|
16
13
|
id;
|
|
17
14
|
deviceType;
|
|
18
15
|
model;
|
|
19
16
|
onData;
|
|
20
|
-
onRequestUpdate = new
|
|
17
|
+
onRequestUpdate = new Subject();
|
|
21
18
|
constructor(initialData, restClient) {
|
|
22
19
|
this.initialData = initialData;
|
|
23
20
|
this.restClient = restClient;
|
|
24
21
|
this.id = this.initialData.id;
|
|
25
22
|
this.deviceType = this.initialData.kind;
|
|
26
|
-
this.model =
|
|
27
|
-
this.onData = new
|
|
23
|
+
this.model = ChimeModel[this.deviceType] || 'Chime';
|
|
24
|
+
this.onData = new BehaviorSubject(this.initialData);
|
|
28
25
|
}
|
|
29
26
|
updateData(update) {
|
|
30
27
|
this.onData.next(update);
|
|
@@ -46,7 +43,7 @@ class RingChime {
|
|
|
46
43
|
}
|
|
47
44
|
getRingtones() {
|
|
48
45
|
return this.restClient.request({
|
|
49
|
-
url:
|
|
46
|
+
url: clientApi('ringtones'),
|
|
50
47
|
});
|
|
51
48
|
}
|
|
52
49
|
async getRingtoneByDescription(description, kind) {
|
|
@@ -59,7 +56,7 @@ class RingChime {
|
|
|
59
56
|
return requestedRingtone;
|
|
60
57
|
}
|
|
61
58
|
chimeUrl(path = '') {
|
|
62
|
-
return
|
|
59
|
+
return clientApi(`chimes/${this.id}/${path}`);
|
|
63
60
|
}
|
|
64
61
|
playSound(kind) {
|
|
65
62
|
return this.restClient.request({
|
|
@@ -106,9 +103,8 @@ class RingChime {
|
|
|
106
103
|
}
|
|
107
104
|
async getHealth() {
|
|
108
105
|
const response = await this.restClient.request({
|
|
109
|
-
url:
|
|
106
|
+
url: clientApi(`chimes/${this.id}/health`),
|
|
110
107
|
});
|
|
111
108
|
return response.device_health;
|
|
112
109
|
}
|
|
113
110
|
}
|
|
114
|
-
exports.RingChime = RingChime;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const device_data_1 = require("./device-data");
|
|
5
|
-
(0, device_data_1.logDeviceData)().catch((e) => {
|
|
2
|
+
import { logDeviceData } from "./device-data.js";
|
|
3
|
+
logDeviceData().catch((e) => {
|
|
6
4
|
// eslint-disable-next-line no-console
|
|
7
5
|
console.error(e);
|
|
8
6
|
process.exit(1);
|
package/lib/ring-device.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import { RingDeviceData } from './ring-types';
|
|
3
|
-
import { Location } from './location';
|
|
4
|
-
import { Subscribed } from './subscribed';
|
|
2
|
+
import type { RingDeviceData } from './ring-types.ts';
|
|
3
|
+
import type { Location } from './location.ts';
|
|
4
|
+
import { Subscribed } from './subscribed.ts';
|
|
5
5
|
export declare class RingDevice extends Subscribed {
|
|
6
6
|
private initialData;
|
|
7
7
|
location: Location;
|
|
@@ -9,7 +9,7 @@ export declare class RingDevice extends Subscribed {
|
|
|
9
9
|
onData: BehaviorSubject<RingDeviceData>;
|
|
10
10
|
zid: string;
|
|
11
11
|
id: string;
|
|
12
|
-
deviceType: import("./ring-types").RingDeviceType;
|
|
12
|
+
deviceType: import("./ring-types.ts").RingDeviceType;
|
|
13
13
|
categoryId: number;
|
|
14
14
|
onComponentDevices: import("rxjs").Observable<RingDevice[]>;
|
|
15
15
|
constructor(initialData: RingDeviceData, location: Location, assetId: string);
|
package/lib/ring-device.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const subscribed_1 = require("./subscribed");
|
|
8
|
-
const util_1 = require("./util");
|
|
9
|
-
class RingDevice extends subscribed_1.Subscribed {
|
|
1
|
+
import { BehaviorSubject } from 'rxjs';
|
|
2
|
+
import { deviceTypesWithVolume } from "./ring-types.js";
|
|
3
|
+
import { filter, map } from 'rxjs/operators';
|
|
4
|
+
import { Subscribed } from "./subscribed.js";
|
|
5
|
+
import { logError } from "./util.js";
|
|
6
|
+
export class RingDevice extends Subscribed {
|
|
10
7
|
initialData;
|
|
11
8
|
location;
|
|
12
9
|
assetId;
|
|
@@ -21,14 +18,14 @@ class RingDevice extends subscribed_1.Subscribed {
|
|
|
21
18
|
this.initialData = initialData;
|
|
22
19
|
this.location = location;
|
|
23
20
|
this.assetId = assetId;
|
|
24
|
-
this.onData = new
|
|
21
|
+
this.onData = new BehaviorSubject(this.initialData);
|
|
25
22
|
this.zid = this.initialData.zid;
|
|
26
23
|
this.id = this.zid;
|
|
27
24
|
this.deviceType = this.initialData.deviceType;
|
|
28
25
|
this.categoryId = this.initialData.categoryId;
|
|
29
|
-
this.onComponentDevices = this.location.onDevices.pipe(
|
|
26
|
+
this.onComponentDevices = this.location.onDevices.pipe(map((devices) => devices.filter(({ data }) => data.parentZid === this.id)));
|
|
30
27
|
this.addSubscriptions(location.onDeviceDataUpdate
|
|
31
|
-
.pipe(
|
|
28
|
+
.pipe(filter((update) => update.zid === this.zid))
|
|
32
29
|
.subscribe((update) => this.updateData(update)));
|
|
33
30
|
}
|
|
34
31
|
updateData(update) {
|
|
@@ -41,7 +38,7 @@ class RingDevice extends subscribed_1.Subscribed {
|
|
|
41
38
|
return this.data.name;
|
|
42
39
|
}
|
|
43
40
|
get supportsVolume() {
|
|
44
|
-
return (
|
|
41
|
+
return (deviceTypesWithVolume.includes(this.data.deviceType) &&
|
|
45
42
|
this.data.volume !== undefined);
|
|
46
43
|
}
|
|
47
44
|
setVolume(volume) {
|
|
@@ -49,7 +46,7 @@ class RingDevice extends subscribed_1.Subscribed {
|
|
|
49
46
|
throw new Error('Volume must be between 0 and 1');
|
|
50
47
|
}
|
|
51
48
|
if (!this.supportsVolume) {
|
|
52
|
-
throw new Error(`Volume can only be set on ${
|
|
49
|
+
throw new Error(`Volume can only be set on ${deviceTypesWithVolume.join(', ')}`);
|
|
53
50
|
}
|
|
54
51
|
return this.setInfo({ device: { v1: { volume } } });
|
|
55
52
|
}
|
|
@@ -76,7 +73,7 @@ class RingDevice extends subscribed_1.Subscribed {
|
|
|
76
73
|
},
|
|
77
74
|
],
|
|
78
75
|
},
|
|
79
|
-
}).catch(
|
|
76
|
+
}).catch(logError);
|
|
80
77
|
}
|
|
81
78
|
toString() {
|
|
82
79
|
return this.toJSON();
|
|
@@ -90,4 +87,3 @@ class RingDevice extends subscribed_1.Subscribed {
|
|
|
90
87
|
this.unsubscribe();
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
|
-
exports.RingDevice = RingDevice;
|
package/lib/ring-intercom.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { IntercomHandsetAudioData, PushNotification } from './ring-types';
|
|
2
|
-
import { RingRestClient } from './rest-client';
|
|
1
|
+
import type { IntercomHandsetAudioData, PushNotification } from './ring-types.ts';
|
|
2
|
+
import type { RingRestClient } from './rest-client.ts';
|
|
3
3
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
4
|
export declare class RingIntercom {
|
|
5
5
|
private initialData;
|
|
6
6
|
private restClient;
|
|
7
7
|
id: number;
|
|
8
|
-
deviceType: import("./ring-types").RingDeviceType.IntercomHandsetAudio;
|
|
8
|
+
deviceType: import("./ring-types.ts").RingDeviceType.IntercomHandsetAudio;
|
|
9
9
|
onData: BehaviorSubject<IntercomHandsetAudioData>;
|
|
10
10
|
onRequestUpdate: Subject<unknown>;
|
|
11
11
|
onBatteryLevel: import("rxjs").Observable<number | null>;
|
|
@@ -18,9 +18,9 @@ export declare class RingIntercom {
|
|
|
18
18
|
get name(): string;
|
|
19
19
|
get isOffline(): boolean;
|
|
20
20
|
get batteryLevel(): number | null;
|
|
21
|
-
unlock(): Promise<import("./rest-client").ExtendedResponse>;
|
|
21
|
+
unlock(): Promise<import("./rest-client.ts").ExtendedResponse>;
|
|
22
22
|
private doorbotUrl;
|
|
23
|
-
subscribeToDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
24
|
-
unsubscribeFromDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
23
|
+
subscribeToDingEvents(): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
24
|
+
unsubscribeFromDingEvents(): Promise<void & import("./rest-client.ts").ExtendedResponse>;
|
|
25
25
|
processPushNotification(notification: PushNotification): void;
|
|
26
26
|
}
|