ring-client-api 11.6.0 → 11.7.0-beta.1
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/README.md +3 -1
- package/lib/api.d.ts +1 -1
- package/lib/api.js +21 -10
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/location.d.ts +3 -1
- package/lib/location.js +2 -1
- package/lib/rest-client.d.ts +1 -0
- package/lib/rest-client.js +6 -2
- package/lib/ring-intercom.d.ts +20 -0
- package/lib/ring-intercom.js +54 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,7 +115,9 @@ camera.getSnapshot() // returns a Promise<Buffer> of the latest snapshot from th
|
|
|
115
115
|
|
|
116
116
|
Camera also includes the following observables:
|
|
117
117
|
|
|
118
|
-
- `
|
|
118
|
+
- `onNewNotification`: this is triggered any time a new push notification is received
|
|
119
|
+
- `onActiveNotifications`: notifications received within the last minute
|
|
120
|
+
- `onDoorbellPressed`: this will include the sip info and ding information every time a new ding is created
|
|
119
121
|
- `onActiveDings`: dings created within the last 65 seconds
|
|
120
122
|
- `onDoorbellPressed`: emits a ding every time the doorbell is pressed
|
|
121
123
|
- `onMotionDetected`: `true` or `false` based on `onActiveDings` containing a motion ding
|
package/lib/api.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export declare class RingApi extends Subscribed {
|
|
|
33
33
|
beamBridges: BeamBridge[];
|
|
34
34
|
onvifCameras: OnvifCameraData[];
|
|
35
35
|
thirdPartyGarageDoorOpeners: ThirdPartyGarageDoorOpener[];
|
|
36
|
-
|
|
36
|
+
intercoms: IntercomHandsetAudioData[];
|
|
37
37
|
unknownDevices: UnknownDevice[];
|
|
38
38
|
}>;
|
|
39
39
|
private listenForDeviceUpdates;
|
package/lib/api.js
CHANGED
|
@@ -15,6 +15,7 @@ const util_1 = require("./util");
|
|
|
15
15
|
const ffmpeg_1 = require("./ffmpeg");
|
|
16
16
|
const subscribed_1 = require("./subscribed");
|
|
17
17
|
const push_receiver_1 = __importDefault(require("@eneris/push-receiver"));
|
|
18
|
+
const ring_intercom_1 = require("./ring-intercom");
|
|
18
19
|
class RingApi extends subscribed_1.Subscribed {
|
|
19
20
|
constructor(options) {
|
|
20
21
|
super();
|
|
@@ -34,14 +35,14 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
async fetchRingDevices() {
|
|
37
|
-
const { doorbots, chimes, authorized_doorbots: authorizedDoorbots, stickup_cams: stickupCams, base_stations: baseStations, beams_bridges: beamBridges, other: otherDevices, } = await this.restClient.request({ url: (0, rest_client_1.clientApi)('ring_devices') }), onvifCameras = [],
|
|
38
|
+
const { doorbots, chimes, authorized_doorbots: authorizedDoorbots, stickup_cams: stickupCams, base_stations: baseStations, beams_bridges: beamBridges, other: otherDevices, } = await this.restClient.request({ url: (0, rest_client_1.clientApi)('ring_devices') }), onvifCameras = [], intercoms = [], thirdPartyGarageDoorOpeners = [], unknownDevices = [];
|
|
38
39
|
otherDevices.forEach((device) => {
|
|
39
40
|
switch (device.kind) {
|
|
40
41
|
case ring_types_1.RingDeviceType.OnvifCamera:
|
|
41
42
|
onvifCameras.push(device);
|
|
42
43
|
break;
|
|
43
44
|
case ring_types_1.RingDeviceType.IntercomHandsetAudio:
|
|
44
|
-
|
|
45
|
+
intercoms.push(device);
|
|
45
46
|
break;
|
|
46
47
|
case ring_types_1.RingDeviceType.ThirdPartyGarageDoorOpener:
|
|
47
48
|
thirdPartyGarageDoorOpeners.push(device);
|
|
@@ -66,16 +67,16 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
66
67
|
beamBridges,
|
|
67
68
|
onvifCameras,
|
|
68
69
|
thirdPartyGarageDoorOpeners,
|
|
69
|
-
|
|
70
|
+
intercoms,
|
|
70
71
|
unknownDevices,
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
|
-
listenForDeviceUpdates(cameras, chimes) {
|
|
74
|
+
listenForDeviceUpdates(cameras, chimes, intercoms) {
|
|
74
75
|
const { cameraStatusPollingSeconds } = this.options;
|
|
75
76
|
if (!cameraStatusPollingSeconds) {
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
|
-
const
|
|
79
|
+
const devices = [...cameras, ...chimes, ...intercoms], onDeviceRequestUpdate = (0, rxjs_1.merge)(...devices.map((device) => device.onRequestUpdate)), onUpdateReceived = new rxjs_1.Subject(), onPollForStatusUpdate = cameraStatusPollingSeconds
|
|
79
80
|
? onUpdateReceived.pipe((0, operators_1.debounceTime)(cameraStatusPollingSeconds * 1000))
|
|
80
81
|
: rxjs_1.EMPTY, camerasById = cameras.reduce((byId, camera) => {
|
|
81
82
|
byId[camera.id] = camera;
|
|
@@ -83,11 +84,14 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
83
84
|
}, {}), chimesById = chimes.reduce((byId, chime) => {
|
|
84
85
|
byId[chime.id] = chime;
|
|
85
86
|
return byId;
|
|
87
|
+
}, {}), intercomsById = intercoms.reduce((byId, intercom) => {
|
|
88
|
+
byId[intercom.id] = intercom;
|
|
89
|
+
return byId;
|
|
86
90
|
}, {});
|
|
87
91
|
if (!cameras.length && !chimes.length) {
|
|
88
92
|
return;
|
|
89
93
|
}
|
|
90
|
-
this.addSubscriptions((0, rxjs_1.merge)(
|
|
94
|
+
this.addSubscriptions((0, rxjs_1.merge)(onDeviceRequestUpdate, onPollForStatusUpdate)
|
|
91
95
|
.pipe((0, operators_1.throttleTime)(500), (0, operators_1.switchMap)(() => this.fetchRingDevices().catch(() => null)))
|
|
92
96
|
.subscribe((response) => {
|
|
93
97
|
onUpdateReceived.next(null);
|
|
@@ -106,6 +110,12 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
106
110
|
chime.updateData(data);
|
|
107
111
|
}
|
|
108
112
|
});
|
|
113
|
+
response.intercoms.forEach((data) => {
|
|
114
|
+
const intercom = intercomsById[data.id];
|
|
115
|
+
if (intercom) {
|
|
116
|
+
intercom.updateData(data);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
109
119
|
}));
|
|
110
120
|
if (cameraStatusPollingSeconds) {
|
|
111
121
|
onUpdateReceived.next(null); // kick off polling
|
|
@@ -142,6 +152,7 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
142
152
|
});
|
|
143
153
|
pushReceiver.onNotification(({ message }) => {
|
|
144
154
|
const dataJson = message.data?.gcmData;
|
|
155
|
+
(0, util_1.logInfo)(`Received push notification: ${dataJson}`);
|
|
145
156
|
try {
|
|
146
157
|
const notification = JSON.parse(dataJson);
|
|
147
158
|
if (!notification.ding) {
|
|
@@ -175,19 +186,19 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
175
186
|
});
|
|
176
187
|
}
|
|
177
188
|
async fetchAndBuildLocations() {
|
|
178
|
-
const rawLocations = await this.fetchRawLocations(), { authorizedDoorbots, chimes, doorbots, allCameras, baseStations, beamBridges, } = await this.fetchRingDevices(), locationIdsWithHubs = [...baseStations, ...beamBridges].map((x) => x.location_id), cameras = allCameras.map((data) => new ring_camera_1.RingCamera(data, doorbots.includes(data) ||
|
|
189
|
+
const rawLocations = await this.fetchRawLocations(), { authorizedDoorbots, chimes, doorbots, allCameras, baseStations, beamBridges, intercoms, } = await this.fetchRingDevices(), locationIdsWithHubs = [...baseStations, ...beamBridges].map((x) => x.location_id), cameras = allCameras.map((data) => new ring_camera_1.RingCamera(data, doorbots.includes(data) ||
|
|
179
190
|
authorizedDoorbots.includes(data) ||
|
|
180
|
-
data.kind.startsWith('doorbell'), this.restClient, this.options.avoidSnapshotBatteryDrain || false)), ringChimes = chimes.map((data) => new ring_chime_1.RingChime(data, this.restClient)), locations = rawLocations
|
|
191
|
+
data.kind.startsWith('doorbell'), this.restClient, this.options.avoidSnapshotBatteryDrain || false)), ringChimes = chimes.map((data) => new ring_chime_1.RingChime(data, this.restClient)), ringIntercoms = intercoms.map((data) => new ring_intercom_1.RingIntercom(data, this.restClient)), locations = rawLocations
|
|
181
192
|
.filter((location) => {
|
|
182
193
|
return (!Array.isArray(this.options.locationIds) ||
|
|
183
194
|
this.options.locationIds.includes(location.location_id));
|
|
184
195
|
})
|
|
185
|
-
.map((location) => new location_1.Location(location, cameras.filter((x) => x.data.location_id === location.location_id), ringChimes.filter((x) => x.data.location_id === location.location_id), {
|
|
196
|
+
.map((location) => new location_1.Location(location, cameras.filter((x) => x.data.location_id === location.location_id), ringChimes.filter((x) => x.data.location_id === location.location_id), ringIntercoms.filter((x) => x.data.location_id === location.location_id), {
|
|
186
197
|
hasHubs: locationIdsWithHubs.includes(location.location_id),
|
|
187
198
|
hasAlarmBaseStation: baseStations.some((station) => station.location_id === location.location_id),
|
|
188
199
|
locationModePollingSeconds: this.options.locationModePollingSeconds,
|
|
189
200
|
}, this.restClient));
|
|
190
|
-
this.listenForDeviceUpdates(cameras, ringChimes);
|
|
201
|
+
this.listenForDeviceUpdates(cameras, ringChimes, ringIntercoms);
|
|
191
202
|
this.registerPushReceiver(cameras).catch((e) => {
|
|
192
203
|
(0, util_1.logError)(e);
|
|
193
204
|
});
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -19,4 +19,5 @@ __exportStar(require("./location"), exports);
|
|
|
19
19
|
__exportStar(require("./ring-camera"), exports);
|
|
20
20
|
__exportStar(require("./ring-chime"), exports);
|
|
21
21
|
__exportStar(require("./ring-device"), exports);
|
|
22
|
+
__exportStar(require("./ring-intercom"), exports);
|
|
22
23
|
__exportStar(require("./ring-types"), exports);
|
package/lib/location.d.ts
CHANGED
|
@@ -5,11 +5,13 @@ import { RingRestClient } from './rest-client';
|
|
|
5
5
|
import { RingCamera } from './ring-camera';
|
|
6
6
|
import { RingChime } from './ring-chime';
|
|
7
7
|
import { RingDevice } from './ring-device';
|
|
8
|
+
import { RingIntercom } from './ring-intercom';
|
|
8
9
|
import { Subscribed } from './subscribed';
|
|
9
10
|
export declare class Location extends Subscribed {
|
|
10
11
|
readonly locationDetails: UserLocation;
|
|
11
12
|
readonly cameras: RingCamera[];
|
|
12
13
|
readonly chimes: RingChime[];
|
|
14
|
+
readonly intercoms: RingIntercom[];
|
|
13
15
|
readonly options: {
|
|
14
16
|
hasHubs: boolean;
|
|
15
17
|
hasAlarmBaseStation: boolean;
|
|
@@ -35,7 +37,7 @@ export declare class Location extends Subscribed {
|
|
|
35
37
|
offlineAssets: string[];
|
|
36
38
|
hasHubs: boolean;
|
|
37
39
|
hasAlarmBaseStation: boolean;
|
|
38
|
-
constructor(locationDetails: UserLocation, cameras: RingCamera[], chimes: RingChime[], options: {
|
|
40
|
+
constructor(locationDetails: UserLocation, cameras: RingCamera[], chimes: RingChime[], intercoms: RingIntercom[], options: {
|
|
39
41
|
hasHubs: boolean;
|
|
40
42
|
hasAlarmBaseStation: boolean;
|
|
41
43
|
locationModePollingSeconds?: number;
|
package/lib/location.js
CHANGED
|
@@ -15,11 +15,12 @@ function flattenDeviceData(data) {
|
|
|
15
15
|
return Object.assign({}, data.general && data.general.v2, data.device && data.device.v1);
|
|
16
16
|
}
|
|
17
17
|
class Location extends subscribed_1.Subscribed {
|
|
18
|
-
constructor(locationDetails, cameras, chimes, options, restClient) {
|
|
18
|
+
constructor(locationDetails, cameras, chimes, intercoms, options, restClient) {
|
|
19
19
|
super();
|
|
20
20
|
this.locationDetails = locationDetails;
|
|
21
21
|
this.cameras = cameras;
|
|
22
22
|
this.chimes = chimes;
|
|
23
|
+
this.intercoms = intercoms;
|
|
23
24
|
this.options = options;
|
|
24
25
|
this.restClient = restClient;
|
|
25
26
|
this.seq = 1;
|
package/lib/rest-client.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { AuthTokenResponse, SessionResponse } from './ring-types';
|
|
|
3
3
|
import { ReplaySubject } from 'rxjs';
|
|
4
4
|
export declare function clientApi(path: string): string;
|
|
5
5
|
export declare function deviceApi(path: string): string;
|
|
6
|
+
export declare function commandsApi(path: string): string;
|
|
6
7
|
export declare function appApi(path: string): string;
|
|
7
8
|
export interface ExtendedResponse {
|
|
8
9
|
responseTimestamp: number;
|
package/lib/rest-client.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.RingRestClient = exports.appApi = exports.deviceApi = exports.clientApi = void 0;
|
|
6
|
+
exports.RingRestClient = exports.appApi = exports.commandsApi = exports.deviceApi = exports.clientApi = void 0;
|
|
7
7
|
const got_1 = __importDefault(require("got"));
|
|
8
8
|
const util_1 = require("./util");
|
|
9
9
|
const rxjs_1 = require("rxjs");
|
|
@@ -18,7 +18,7 @@ const defaultRequestOptions = {
|
|
|
18
18
|
7061: 'ASSET_CELL_BACKUP',
|
|
19
19
|
7062: 'UPDATING',
|
|
20
20
|
7063: 'MAINTENANCE',
|
|
21
|
-
}, clientApiBaseUrl = 'https://api.ring.com/clients_api/', deviceApiBaseUrl = 'https://api.ring.com/devices/v1/', appApiBaseUrl = 'https://app.ring.com/api/v1/', apiVersion = 11;
|
|
21
|
+
}, clientApiBaseUrl = 'https://api.ring.com/clients_api/', deviceApiBaseUrl = 'https://api.ring.com/devices/v1/', commandsApiBaseUrl = 'https://api.ring.com/commands/v1/', appApiBaseUrl = 'https://app.ring.com/api/v1/', apiVersion = 11;
|
|
22
22
|
function clientApi(path) {
|
|
23
23
|
return clientApiBaseUrl + path;
|
|
24
24
|
}
|
|
@@ -27,6 +27,10 @@ function deviceApi(path) {
|
|
|
27
27
|
return deviceApiBaseUrl + path;
|
|
28
28
|
}
|
|
29
29
|
exports.deviceApi = deviceApi;
|
|
30
|
+
function commandsApi(path) {
|
|
31
|
+
return commandsApiBaseUrl + path;
|
|
32
|
+
}
|
|
33
|
+
exports.commandsApi = commandsApi;
|
|
30
34
|
function appApi(path) {
|
|
31
35
|
return appApiBaseUrl + path;
|
|
32
36
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IntercomHandsetAudioData } from './ring-types';
|
|
2
|
+
import { RingRestClient } from './rest-client';
|
|
3
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
|
+
export declare class RingIntercom {
|
|
5
|
+
private initialData;
|
|
6
|
+
private restClient;
|
|
7
|
+
id: number;
|
|
8
|
+
deviceType: import("./ring-types").RingDeviceType.IntercomHandsetAudio;
|
|
9
|
+
onData: BehaviorSubject<IntercomHandsetAudioData>;
|
|
10
|
+
onRequestUpdate: Subject<unknown>;
|
|
11
|
+
onBatteryLevel: import("rxjs").Observable<number | null>;
|
|
12
|
+
constructor(initialData: IntercomHandsetAudioData, restClient: RingRestClient);
|
|
13
|
+
updateData(update: IntercomHandsetAudioData): void;
|
|
14
|
+
requestUpdate(): void;
|
|
15
|
+
get data(): IntercomHandsetAudioData;
|
|
16
|
+
get name(): string;
|
|
17
|
+
get isOffline(): boolean;
|
|
18
|
+
get batteryLevel(): number | null;
|
|
19
|
+
unlock(): Promise<import("./rest-client").ExtendedResponse>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RingIntercom = void 0;
|
|
4
|
+
const rest_client_1 = require("./rest-client");
|
|
5
|
+
const rxjs_1 = require("rxjs");
|
|
6
|
+
const operators_1 = require("rxjs/operators");
|
|
7
|
+
const ring_camera_1 = require("./ring-camera");
|
|
8
|
+
class RingIntercom {
|
|
9
|
+
constructor(initialData, restClient) {
|
|
10
|
+
this.initialData = initialData;
|
|
11
|
+
this.restClient = restClient;
|
|
12
|
+
this.onRequestUpdate = new rxjs_1.Subject();
|
|
13
|
+
this.id = this.initialData.id;
|
|
14
|
+
this.deviceType = this.initialData.kind;
|
|
15
|
+
this.onData = new rxjs_1.BehaviorSubject(this.initialData);
|
|
16
|
+
this.onBatteryLevel = this.onData.pipe((0, operators_1.map)((data) => (0, ring_camera_1.getBatteryLevel)(data)), (0, operators_1.distinctUntilChanged)());
|
|
17
|
+
}
|
|
18
|
+
updateData(update) {
|
|
19
|
+
this.onData.next(update);
|
|
20
|
+
}
|
|
21
|
+
requestUpdate() {
|
|
22
|
+
this.onRequestUpdate.next(null);
|
|
23
|
+
}
|
|
24
|
+
get data() {
|
|
25
|
+
return this.onData.getValue();
|
|
26
|
+
}
|
|
27
|
+
get name() {
|
|
28
|
+
return this.data.description;
|
|
29
|
+
}
|
|
30
|
+
get isOffline() {
|
|
31
|
+
return this.data.alerts.connection === 'offline';
|
|
32
|
+
}
|
|
33
|
+
get batteryLevel() {
|
|
34
|
+
return (0, ring_camera_1.getBatteryLevel)(this.data);
|
|
35
|
+
}
|
|
36
|
+
unlock() {
|
|
37
|
+
return this.restClient.request({
|
|
38
|
+
method: 'PUT',
|
|
39
|
+
url: (0, rest_client_1.commandsApi)(`devices/${this.id}/device_rpc`),
|
|
40
|
+
json: {
|
|
41
|
+
command_name: 'device_rpc',
|
|
42
|
+
request: {
|
|
43
|
+
jsonrpc: '2.0',
|
|
44
|
+
method: 'unlock_door',
|
|
45
|
+
params: {
|
|
46
|
+
door_id: this.id,
|
|
47
|
+
user_id: 0,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.RingIntercom = RingIntercom;
|