homebridge-ring 10.0.0-beta.4 → 10.0.0-beta.7
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 +43 -0
- package/README.md +2 -5
- package/config.schema.json +4 -10
- package/lib/api/api.js +3 -5
- package/lib/api/index.js +5 -1
- package/lib/api/rest-client.d.ts +5 -0
- package/lib/api/rest-client.js +7 -6
- package/lib/api/ring-camera.d.ts +16 -5
- package/lib/api/ring-camera.js +43 -9
- package/lib/api/ring-types.d.ts +1 -0
- package/lib/api/ring-types.js +2 -0
- package/lib/api/{peer-connection.d.ts → streaming/peer-connection.d.ts} +21 -4
- package/lib/api/{peer-connection.js → streaming/peer-connection.js} +4 -4
- package/lib/api/streaming/ring-edge-connection.d.ts +65 -0
- package/lib/api/streaming/ring-edge-connection.js +155 -0
- package/lib/api/streaming/simple-webrtc-session.d.ts +11 -0
- package/lib/api/streaming/simple-webrtc-session.js +63 -0
- package/lib/api/streaming/streaming-connection-base.d.ts +30 -0
- package/lib/api/streaming/streaming-connection-base.js +111 -0
- package/lib/api/{live-call.d.ts → streaming/streaming-session.d.ts} +15 -18
- package/lib/api/{live-call.js → streaming/streaming-session.js} +32 -94
- package/lib/api/streaming/webrtc-connection.d.ts +23 -0
- package/lib/api/streaming/webrtc-connection.js +60 -0
- package/lib/api/util.js +7 -0
- package/lib/homebridge/camera-source.js +2 -2
- package/lib/homebridge/camera.js +2 -17
- package/lib/homebridge/config.d.ts +0 -2
- package/lib/test/api/ring-camera.spec.d.ts +1 -0
- package/lib/test/api/ring-camera.spec.js +25 -0
- package/package.json +32 -29
- package/lib/api/live-call-ring-edge.d.ts +0 -41
- package/lib/api/live-call-ring-edge.js +0 -294
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [10.0.0-beta.7](https://github.com/dgreif/ring/compare/v10.0.0-beta.6...v10.0.0-beta.7) (2022-05-07)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
* The `sendDoorbellMotionNotificationsToTv` and `sendCameraMotionNotificationsToTv` options have been removed. These options were originally inteded as a workaround for the fact that tvOS would only automatically start streaming for doorbell presses and not for motion events. tvOS 15 now supports this features as an option in the UI, so we no longer need this option at the plugin level.
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* add `cocoa_floodlight` ([c7a7e9c](https://github.com/dgreif/ring/commit/c7a7e9cabf45ec6579a7d9a1033fa01930923243)), closes [#893](https://github.com/dgreif/ring/issues/893)
|
|
15
|
+
* **api:** simple webrtc session ([bac7a49](https://github.com/dgreif/ring/commit/bac7a49178bb5a22914e53fda91c0fdd522b4a74))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **homebridge:** add `name` option to schema so that it won't be removed by config-ui ([af6755a](https://github.com/dgreif/ring/commit/af6755aa09cf4aaad0963499ad0d1afd0beeab96)), closes [#870](https://github.com/dgreif/ring/issues/870)
|
|
21
|
+
* include device name when setting push token ([2466a25](https://github.com/dgreif/ring/commit/2466a2519341771d8c79557b5a61c339f31eddf6)), closes [#920](https://github.com/dgreif/ring/issues/920)
|
|
22
|
+
* npm audit fix ([c1fe605](https://github.com/dgreif/ring/commit/c1fe6051e46dac92b00bb2fd1202746fd576b15a))
|
|
23
|
+
* remove doorbell press simulation options ([e1d1225](https://github.com/dgreif/ring/commit/e1d12257b2acbdafdc6995a53d9052822c8a3460))
|
|
24
|
+
|
|
25
|
+
## [10.0.0-beta.6](https://github.com/dgreif/ring/compare/v10.0.0-beta.5...v10.0.0-beta.6) (2022-05-06)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* **api:** allow custom peer connections for streaming ([3e9e784](https://github.com/dgreif/ring/commit/3e9e78458afe2849a8c414a6b50eec8718bf77cc))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* update dependencies ([4b25595](https://github.com/dgreif/ring/commit/4b255950bcfbf94486192d55cfc90d966cd79d24))
|
|
36
|
+
|
|
37
|
+
## [10.0.0-beta.5](https://github.com/dgreif/ring/compare/v10.0.0-beta.4...v10.0.0-beta.5) (2022-04-10)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Bug Fixes
|
|
41
|
+
|
|
42
|
+
* **cameras:** wait to activate session until connected ([9a49389](https://github.com/dgreif/ring/commit/9a49389aa434cc5df4cfb4ba039bad0f2a30f756))
|
|
43
|
+
* handle push notification for unknown camera ([cc8fc2a](https://github.com/dgreif/ring/commit/cc8fc2a6377084515d3b169a85644b2a2b13235e))
|
|
44
|
+
* hide ECONNRESET errors from push receiver ([1196d96](https://github.com/dgreif/ring/commit/1196d96e67e26952f18dfbe75103419a7261bd1e))
|
|
45
|
+
* restore dual battery level calculations ([26fa84d](https://github.com/dgreif/ring/commit/26fa84dbd4bbcea8208fd0ade81c54c407aabf63))
|
|
46
|
+
* update dependencies ([4b97fb3](https://github.com/dgreif/ring/commit/4b97fb33623248147997944bab3de4ea3c2e5ee2))
|
|
47
|
+
|
|
5
48
|
## [10.0.0-beta.4](https://github.com/dgreif/ring/compare/v10.0.0-beta.3...v10.0.0-beta.4) (2022-04-03)
|
|
6
49
|
|
|
7
50
|
|
package/README.md
CHANGED
|
@@ -59,8 +59,6 @@ Only include an optional parameter if you actually need it. Default behavior wi
|
|
|
59
59
|
"hideDoorbellSwitch": true,
|
|
60
60
|
"hideCameraLight": true,
|
|
61
61
|
"hideCameraMotionSensor": true,
|
|
62
|
-
"sendCameraMotionNotificationsToTv": true,
|
|
63
|
-
"sendDoorbellMotionNotificationsToTv": true,
|
|
64
62
|
"hideCameraSirenSwitch": true,
|
|
65
63
|
"hideInHomeDoorbellSwitch": true,
|
|
66
64
|
"hideAlarmSirenSwitch": true,
|
|
@@ -82,8 +80,6 @@ Option | Default | Explanation
|
|
|
82
80
|
`hideDoorbellSwitch` | `false` | If you have a Ring video doorbell, you will see a Programmable Switch associated with it. This switch can be used to perform actions on when the doorbell is pressed using "Single Press" actions. If you do not care to perform actions when the doorbell is pressed, you can hide the Programmable Switch by setting this option to `true`. You will still be able to receive _notifications_ from the doorbell even if the Programmable Switch is hidden (notifications can be configured in the settings for the doorbell camera in the Home app)
|
|
83
81
|
`hideCameraLight` | `false` | If `true`, hides the light for Ring cameras in HomeKit.
|
|
84
82
|
`hideCameraMotionSensor` | `false` | If `true`, hides the motion sensor for Ring cameras in HomeKit.
|
|
85
|
-
`sendCameraMotionNotificationsToTv` | `false` | If `true`, creates a 'Doorbell' accessory triggered by non-doorbell camera motion alerts for tvOS 14 notification support.
|
|
86
|
-
`sendDoorbellMotionNotificationsToTv` | `false` | If `true`, motion events on doorbell cameras will trigger a doorbell press event for tvOS 14 notification support.
|
|
87
83
|
`hideCameraSirenSwitch` | `false` | If `true`, hides the siren switch for Ring cameras in HomeKit.
|
|
88
84
|
`hideInHomeDoorbellSwitch` | `false` | If `true`, hides the switch for in-home doorbells in HomeKit.
|
|
89
85
|
`hideAlarmSirenSwitch` | `false` | If you have a Ring Alarm, you will see both the alarm and a "Siren" switch in HomeKit. The siren switch can sometimes get triggered by Siri commands by accident, which is loud and annoying. Set this option to `true` to hide the siren switch.
|
|
@@ -105,7 +101,6 @@ Option | Default | Explanation
|
|
|
105
101
|
* Shows a live feed from the camera if you click on it. The feed supports video and 2-way audio, but requires that you have `ffmpeg` with `libfdk_aac` installed. A pre-built `ffmpeg` will be automatically installed on most platforms using `ffmpeg-for-homebridge`. See the [FFmpeg wiki](https://github.com/dgreif/ring/wiki/FFmpeg) for details.
|
|
106
102
|
* Motion Sensor
|
|
107
103
|
* Can be hidden with `hideCameraMotionSensor`
|
|
108
|
-
* Can trigger doorbell events with `sendCameraMotionNotificationsToTv` and `sendDoorbellMotionNotificationsToTv` for tvOS 14 notifications
|
|
109
104
|
* Light (if camera is equipped)
|
|
110
105
|
* Siren Switch (if camera is equipped)
|
|
111
106
|
* Can be hidden with `hideCameraSirenSwitch`
|
|
@@ -121,6 +116,8 @@ HomeKit with a snapshot from the camera
|
|
|
121
116
|
|
|
122
117
|
If you are having issues with your cameras in the Home app, please see the [Camera Troubleshooting Wiki](https://github.com/dgreif/ring/wiki/Camera-Troubleshooting)
|
|
123
118
|
|
|
119
|
+
Note: Although homebridge has support for HomeKit Secure Video (HKSV), I will not be adding it to this plugin. Please see [this issue](https://github.com/dgreif/ring/issues/860#issuecomment-1021584211) for more details.
|
|
120
|
+
|
|
124
121
|
### Supported Devices via Ring Alarm and Ring Smart Lighting Hubs
|
|
125
122
|
* Security Panel
|
|
126
123
|
* This is a software device that represents the alarm for a Ring location
|
package/config.schema.json
CHANGED
|
@@ -86,14 +86,6 @@
|
|
|
86
86
|
"type": "boolean",
|
|
87
87
|
"description": "Causes snapshots for battery cameras to be fetched at a minimum 10 minute interval to avoid draining the battery. This is useful if have the Home app open constantly, causing frequent snapshot requests."
|
|
88
88
|
},
|
|
89
|
-
"sendCameraMotionNotificationsToTv": {
|
|
90
|
-
"title": "Create a 'Doorbell' accessory triggered by non-doorbell camera motion alerts for tvOS 14 notification support",
|
|
91
|
-
"type": "boolean"
|
|
92
|
-
},
|
|
93
|
-
"sendDoorbellMotionNotificationsToTv": {
|
|
94
|
-
"title": "Motion events on doorbell cameras will trigger a doorbell press event for tvOS 14 notification support.",
|
|
95
|
-
"type": "boolean"
|
|
96
|
-
},
|
|
97
89
|
"beamDurationSeconds": {
|
|
98
90
|
"title": "Ring Smart Lighting Timer",
|
|
99
91
|
"type": "integer",
|
|
@@ -140,6 +132,10 @@
|
|
|
140
132
|
"items": {
|
|
141
133
|
"type": "string"
|
|
142
134
|
}
|
|
135
|
+
},
|
|
136
|
+
"name": {
|
|
137
|
+
"title": "Name",
|
|
138
|
+
"type": "string"
|
|
143
139
|
}
|
|
144
140
|
},
|
|
145
141
|
"required": ["refreshToken"]
|
|
@@ -167,8 +163,6 @@
|
|
|
167
163
|
"showPanicButtons",
|
|
168
164
|
"nightModeBypassFor",
|
|
169
165
|
"avoidSnapshotBatteryDrain",
|
|
170
|
-
"sendCameraMotionNotificationsToTv",
|
|
171
|
-
"sendDoorbellMotionNotificationsToTv",
|
|
172
166
|
"beamDurationSeconds",
|
|
173
167
|
"debug",
|
|
174
168
|
"cameraStatusPollingSeconds",
|
package/lib/api/api.js
CHANGED
|
@@ -112,9 +112,7 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
112
112
|
method: 'PATCH',
|
|
113
113
|
json: {
|
|
114
114
|
device: {
|
|
115
|
-
metadata: {
|
|
116
|
-
pn_service: 'fcm',
|
|
117
|
-
},
|
|
115
|
+
metadata: Object.assign(Object.assign({}, this.restClient.baseSessionMetadata), { pn_service: 'fcm' }),
|
|
118
116
|
os: 'android',
|
|
119
117
|
push_notification_token: token,
|
|
120
118
|
},
|
|
@@ -126,7 +124,7 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
126
124
|
}
|
|
127
125
|
}));
|
|
128
126
|
pushReceiver.onNotification(({ message }) => {
|
|
129
|
-
var _a;
|
|
127
|
+
var _a, _b;
|
|
130
128
|
const dataJson = (_a = message.data) === null || _a === void 0 ? void 0 : _a.gcmData;
|
|
131
129
|
try {
|
|
132
130
|
const notification = JSON.parse(dataJson);
|
|
@@ -134,7 +132,7 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
134
132
|
// We may get notification that are not for a ding/motion, which can be ignored
|
|
135
133
|
return;
|
|
136
134
|
}
|
|
137
|
-
camerasById[notification.ding.doorbot_id].processPushNotification(notification);
|
|
135
|
+
(_b = camerasById[notification.ding.doorbot_id]) === null || _b === void 0 ? void 0 : _b.processPushNotification(notification);
|
|
138
136
|
}
|
|
139
137
|
catch (e) {
|
|
140
138
|
(0, util_1.logError)(e);
|
package/lib/api/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/lib/api/rest-client.d.ts
CHANGED
|
@@ -35,6 +35,10 @@ export declare class RingRestClient {
|
|
|
35
35
|
oldRefreshToken?: string | undefined;
|
|
36
36
|
newRefreshToken: string;
|
|
37
37
|
}>;
|
|
38
|
+
readonly baseSessionMetadata: {
|
|
39
|
+
api_version: number;
|
|
40
|
+
device_model: string;
|
|
41
|
+
};
|
|
38
42
|
constructor(authOptions: (EmailAuth | RefreshTokenAuth) & SessionOptions);
|
|
39
43
|
private getGrantData;
|
|
40
44
|
getAuth(twoFactorAuthCode?: string): Promise<AuthTokenResponse>;
|
|
@@ -44,6 +48,7 @@ export declare class RingRestClient {
|
|
|
44
48
|
private refreshSession;
|
|
45
49
|
request<T = void>(options: RequestOptions & {
|
|
46
50
|
url: string;
|
|
51
|
+
allowNoResponse?: boolean;
|
|
47
52
|
}): Promise<T & ExtendedResponse>;
|
|
48
53
|
getCurrentAuth(): Promise<AuthTokenResponse>;
|
|
49
54
|
clearTimeouts(): void;
|
package/lib/api/rest-client.js
CHANGED
|
@@ -55,7 +55,7 @@ function requestWithRetry(requestOptions) {
|
|
|
55
55
|
return data;
|
|
56
56
|
}
|
|
57
57
|
catch (e) {
|
|
58
|
-
if (!e.response) {
|
|
58
|
+
if (!e.response && !requestOptions.allowNoResponse) {
|
|
59
59
|
(0, util_1.logError)(`Failed to reach Ring server at ${requestOptions.url}. ${e.message}. Trying again in 5 seconds...`);
|
|
60
60
|
if (e.message.includes('NGHTTP2_ENHANCE_YOUR_CALM')) {
|
|
61
61
|
(0, util_1.logError)(`There is a known issue with your current NodeJS version (${process.version}). Please see https://github.com/dgreif/ring/wiki/NGHTTP2_ENHANCE_YOUR_CALM-Error for details`);
|
|
@@ -70,11 +70,16 @@ function requestWithRetry(requestOptions) {
|
|
|
70
70
|
}
|
|
71
71
|
class RingRestClient {
|
|
72
72
|
constructor(authOptions) {
|
|
73
|
+
var _a;
|
|
73
74
|
this.authOptions = authOptions;
|
|
74
75
|
this.timeouts = [];
|
|
75
76
|
this.sessionPromise = undefined;
|
|
76
77
|
this.using2fa = false;
|
|
77
78
|
this.onRefreshTokenUpdated = new rxjs_1.ReplaySubject(1);
|
|
79
|
+
this.baseSessionMetadata = {
|
|
80
|
+
api_version: apiVersion,
|
|
81
|
+
device_model: (_a = this.authOptions.controlCenterDisplayName) !== null && _a !== void 0 ? _a : 'ring-client-api',
|
|
82
|
+
};
|
|
78
83
|
this.refreshToken =
|
|
79
84
|
'refreshToken' in this.authOptions
|
|
80
85
|
? this.authOptions.refreshToken
|
|
@@ -184,17 +189,13 @@ class RingRestClient {
|
|
|
184
189
|
});
|
|
185
190
|
}
|
|
186
191
|
fetchNewSession(authToken) {
|
|
187
|
-
var _a;
|
|
188
192
|
return __awaiter(this, void 0, void 0, function* () {
|
|
189
193
|
return requestWithRetry({
|
|
190
194
|
url: clientApi('session'),
|
|
191
195
|
json: {
|
|
192
196
|
device: {
|
|
193
197
|
hardware_id: yield this.hardwareIdPromise,
|
|
194
|
-
metadata:
|
|
195
|
-
api_version: apiVersion,
|
|
196
|
-
device_model: (_a = this.authOptions.controlCenterDisplayName) !== null && _a !== void 0 ? _a : 'ring-client-api',
|
|
197
|
-
},
|
|
198
|
+
metadata: this.baseSessionMetadata,
|
|
198
199
|
os: 'android', // can use android, ios, ring-site, windows for sure
|
|
199
200
|
},
|
|
200
201
|
},
|
package/lib/api/ring-camera.d.ts
CHANGED
|
@@ -4,9 +4,12 @@ import { RingRestClient } from './rest-client';
|
|
|
4
4
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
5
5
|
import { DeepPartial } from './util';
|
|
6
6
|
import { Subscribed } from './subscribed';
|
|
7
|
-
import { FfmpegOptions,
|
|
8
|
-
import {
|
|
9
|
-
|
|
7
|
+
import { FfmpegOptions, StreamingSession } from './streaming/streaming-session';
|
|
8
|
+
import { StreamingConnectionOptions } from './streaming/streaming-connection-base';
|
|
9
|
+
import { SimpleWebRtcSession } from './streaming/simple-webrtc-session';
|
|
10
|
+
export declare function getBatteryLevel(data: Pick<CameraData, 'battery_life' | 'battery_life_2'> & {
|
|
11
|
+
health?: Partial<CameraData['health']>;
|
|
12
|
+
}): number | null;
|
|
10
13
|
export declare function getSearchQueryString(options: CameraEventOptions | (HistoryOptions & {
|
|
11
14
|
accountId: string;
|
|
12
15
|
})): string;
|
|
@@ -53,7 +56,8 @@ export declare class RingCamera extends Subscribed {
|
|
|
53
56
|
getDeviceSettings(): Promise<CameraDeviceSettingsData & import("./rest-client").ExtendedResponse>;
|
|
54
57
|
setInHomeDoorbell(enable: boolean): Promise<boolean>;
|
|
55
58
|
getHealth(): Promise<CameraHealth>;
|
|
56
|
-
|
|
59
|
+
private createStreamingConnection;
|
|
60
|
+
startLiveCall(options?: StreamingConnectionOptions): Promise<StreamingSession>;
|
|
57
61
|
private removeDingById;
|
|
58
62
|
processPushNotification(notification: PushNotification): void;
|
|
59
63
|
getEvents(options?: CameraEventOptions): Promise<CameraEventResponse & import("./rest-client").ExtendedResponse>;
|
|
@@ -91,7 +95,14 @@ export declare class RingCamera extends Subscribed {
|
|
|
91
95
|
}): Promise<Buffer & import("./rest-client").ExtendedResponse>;
|
|
92
96
|
getSnapshotByUuid(uuid: string): Promise<Buffer & import("./rest-client").ExtendedResponse>;
|
|
93
97
|
recordToFile(outputPath: string, duration?: number): Promise<void>;
|
|
94
|
-
streamVideo(ffmpegOptions: FfmpegOptions): Promise<
|
|
98
|
+
streamVideo(ffmpegOptions: FfmpegOptions): Promise<StreamingSession>;
|
|
99
|
+
/**
|
|
100
|
+
* Returns a SimpleWebRtcSession, which can be initiated with an sdp offer.
|
|
101
|
+
* This session has no backplane for trickle ICE, and is designed for use in a
|
|
102
|
+
* browser setting. Note, cameras with Ring Edge enabled will stream with the speaker
|
|
103
|
+
* enabled as soon as the stream starts, which can drain the battery more quickly.
|
|
104
|
+
*/
|
|
105
|
+
createSimpleWebRtcSession(): SimpleWebRtcSession;
|
|
95
106
|
subscribeToDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
96
107
|
unsubscribeFromDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
97
108
|
subscribeToMotionEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
package/lib/api/ring-camera.js
CHANGED
|
@@ -16,20 +16,39 @@ const rxjs_1 = require("rxjs");
|
|
|
16
16
|
const operators_1 = require("rxjs/operators");
|
|
17
17
|
const util_1 = require("./util");
|
|
18
18
|
const subscribed_1 = require("./subscribed");
|
|
19
|
-
const
|
|
20
|
-
const
|
|
19
|
+
const webrtc_connection_1 = require("./streaming/webrtc-connection");
|
|
20
|
+
const ring_edge_connection_1 = require("./streaming/ring-edge-connection");
|
|
21
|
+
const streaming_session_1 = require("./streaming/streaming-session");
|
|
22
|
+
const simple_webrtc_session_1 = require("./streaming/simple-webrtc-session");
|
|
21
23
|
const maxSnapshotRefreshSeconds = 15, fullDayMs = 24 * 60 * 60 * 1000;
|
|
24
|
+
function parseBatteryLife(batteryLife) {
|
|
25
|
+
if (batteryLife === null || batteryLife === undefined) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const batteryLevel = typeof batteryLife === 'number'
|
|
29
|
+
? batteryLife
|
|
30
|
+
: Number.parseFloat(batteryLife);
|
|
31
|
+
if (isNaN(batteryLevel)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return batteryLevel;
|
|
35
|
+
}
|
|
22
36
|
function getStartOfToday() {
|
|
23
37
|
return new Date(new Date().toLocaleDateString()).getTime();
|
|
24
38
|
}
|
|
25
39
|
function getEndOfToday() {
|
|
26
40
|
return getStartOfToday() + fullDayMs - 1;
|
|
27
41
|
}
|
|
28
|
-
function getBatteryLevel(
|
|
29
|
-
|
|
42
|
+
function getBatteryLevel(data) {
|
|
43
|
+
const levels = [
|
|
44
|
+
parseBatteryLife(data.battery_life),
|
|
45
|
+
parseBatteryLife(data.battery_life_2),
|
|
46
|
+
].filter((level) => level !== null), { health } = data;
|
|
47
|
+
if (!levels.length ||
|
|
48
|
+
(health && !health.battery_percentage && !health.battery_present)) {
|
|
30
49
|
return null;
|
|
31
50
|
}
|
|
32
|
-
return
|
|
51
|
+
return Math.min(...levels);
|
|
33
52
|
}
|
|
34
53
|
exports.getBatteryLevel = getBatteryLevel;
|
|
35
54
|
function getSearchQueryString(options) {
|
|
@@ -117,7 +136,7 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
117
136
|
return this.data.alerts.battery === 'low';
|
|
118
137
|
}
|
|
119
138
|
get isCharging() {
|
|
120
|
-
return
|
|
139
|
+
return this.initialData.external_connection;
|
|
121
140
|
}
|
|
122
141
|
get operatingOnBattery() {
|
|
123
142
|
return this.hasBattery && this.data.settings.power_mode !== 'wired';
|
|
@@ -212,11 +231,11 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
212
231
|
return response.device_health;
|
|
213
232
|
});
|
|
214
233
|
}
|
|
215
|
-
|
|
234
|
+
createStreamingConnection(options) {
|
|
216
235
|
return __awaiter(this, void 0, void 0, function* () {
|
|
217
236
|
if (this.isRingEdgeEnabled) {
|
|
218
237
|
const auth = yield this.restClient.getCurrentAuth();
|
|
219
|
-
return new
|
|
238
|
+
return new ring_edge_connection_1.RingEdgeConnection(auth.access_token, this, options);
|
|
220
239
|
}
|
|
221
240
|
const liveCall = yield this.restClient
|
|
222
241
|
.request({
|
|
@@ -232,7 +251,13 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
232
251
|
}
|
|
233
252
|
throw e;
|
|
234
253
|
});
|
|
235
|
-
return new
|
|
254
|
+
return new webrtc_connection_1.WebrtcConnection(liveCall.data.session_id, this, options);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
startLiveCall(options = {}) {
|
|
258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
259
|
+
const connection = yield this.createStreamingConnection(options);
|
|
260
|
+
return new streaming_session_1.StreamingSession(this, connection);
|
|
236
261
|
});
|
|
237
262
|
}
|
|
238
263
|
removeDingById(idToRemove) {
|
|
@@ -392,6 +417,15 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
392
417
|
return liveCall;
|
|
393
418
|
});
|
|
394
419
|
}
|
|
420
|
+
/**
|
|
421
|
+
* Returns a SimpleWebRtcSession, which can be initiated with an sdp offer.
|
|
422
|
+
* This session has no backplane for trickle ICE, and is designed for use in a
|
|
423
|
+
* browser setting. Note, cameras with Ring Edge enabled will stream with the speaker
|
|
424
|
+
* enabled as soon as the stream starts, which can drain the battery more quickly.
|
|
425
|
+
*/
|
|
426
|
+
createSimpleWebRtcSession() {
|
|
427
|
+
return new simple_webrtc_session_1.SimpleWebRtcSession(this, this.restClient);
|
|
428
|
+
}
|
|
395
429
|
subscribeToDingEvents() {
|
|
396
430
|
return this.restClient.request({
|
|
397
431
|
method: 'POST',
|
package/lib/api/ring-types.d.ts
CHANGED
|
@@ -85,6 +85,7 @@ export declare enum RingCameraKind {
|
|
|
85
85
|
floodlight_pro = "floodlight_pro",
|
|
86
86
|
cocoa_camera = "cocoa_camera",
|
|
87
87
|
cocoa_doorbell = "cocoa_doorbell",
|
|
88
|
+
cocoa_floodlight = "cocoa_floodlight",
|
|
88
89
|
stickup_cam_mini = "stickup_cam_mini"
|
|
89
90
|
}
|
|
90
91
|
export declare const RingCameraModel: {
|
package/lib/api/ring-types.js
CHANGED
|
@@ -93,6 +93,7 @@ var RingCameraKind;
|
|
|
93
93
|
RingCameraKind["floodlight_pro"] = "floodlight_pro";
|
|
94
94
|
RingCameraKind["cocoa_camera"] = "cocoa_camera";
|
|
95
95
|
RingCameraKind["cocoa_doorbell"] = "cocoa_doorbell";
|
|
96
|
+
RingCameraKind["cocoa_floodlight"] = "cocoa_floodlight";
|
|
96
97
|
RingCameraKind["stickup_cam_mini"] = "stickup_cam_mini";
|
|
97
98
|
})(RingCameraKind = exports.RingCameraKind || (exports.RingCameraKind = {}));
|
|
98
99
|
exports.RingCameraModel = {
|
|
@@ -121,6 +122,7 @@ exports.RingCameraModel = {
|
|
|
121
122
|
floodlight_pro: 'Floodlight Pro',
|
|
122
123
|
cocoa_camera: 'Stick Up Cam',
|
|
123
124
|
cocoa_doorbell: 'Doorbell Gen 2',
|
|
125
|
+
cocoa_floodlight: 'Floodlight Cam Plus',
|
|
124
126
|
stickup_cam_mini: 'Indoor Cam',
|
|
125
127
|
};
|
|
126
128
|
exports.allAlarmStates = [
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import { MediaStreamTrack, RTCIceCandidate,
|
|
2
|
-
import { ReplaySubject, Subject } from 'rxjs';
|
|
3
|
-
export
|
|
4
|
-
|
|
1
|
+
import { ConnectionState, MediaStreamTrack, RTCIceCandidate, RtcpPacket, RtpPacket } from '@koush/werift';
|
|
2
|
+
import { Observable, ReplaySubject, Subject } from 'rxjs';
|
|
3
|
+
export interface BasicPeerConnection {
|
|
4
|
+
createOffer(): Promise<{
|
|
5
|
+
sdp: string;
|
|
6
|
+
}>;
|
|
7
|
+
createAnswer(offer: {
|
|
8
|
+
type: 'offer';
|
|
9
|
+
sdp: string;
|
|
10
|
+
}): Promise<RTCSessionDescriptionInit>;
|
|
11
|
+
acceptAnswer(answer: {
|
|
12
|
+
type: 'answer';
|
|
13
|
+
sdp: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
addIceCandidate(candidate: RTCIceCandidate): Promise<void>;
|
|
16
|
+
onIceCandidate: Observable<RTCIceCandidate>;
|
|
17
|
+
onConnectionState: Observable<ConnectionState>;
|
|
18
|
+
close(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare class WeriftPeerConnection implements BasicPeerConnection {
|
|
21
|
+
private pc;
|
|
5
22
|
onAudioRtp: Subject<RtpPacket>;
|
|
6
23
|
onAudioRtcp: Subject<RtcpPacket>;
|
|
7
24
|
onVideoRtp: Subject<RtpPacket>;
|
|
@@ -9,10 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
12
|
+
exports.WeriftPeerConnection = void 0;
|
|
13
13
|
const werift_1 = require("@koush/werift");
|
|
14
14
|
const rxjs_1 = require("rxjs");
|
|
15
|
-
const util_1 = require("
|
|
15
|
+
const util_1 = require("../util");
|
|
16
16
|
const debug = false, ringIceServers = [
|
|
17
17
|
'stun:stun.kinesisvideo.us-east-1.amazonaws.com:443',
|
|
18
18
|
'stun:stun.kinesisvideo.us-east-2.amazonaws.com:443',
|
|
@@ -23,7 +23,7 @@ const debug = false, ringIceServers = [
|
|
|
23
23
|
'stun:stun3.l.google.com:19302',
|
|
24
24
|
'stun:stun4.l.google.com:19302',
|
|
25
25
|
];
|
|
26
|
-
class
|
|
26
|
+
class WeriftPeerConnection {
|
|
27
27
|
constructor() {
|
|
28
28
|
this.onAudioRtp = new rxjs_1.Subject();
|
|
29
29
|
this.onAudioRtcp = new rxjs_1.Subject();
|
|
@@ -131,4 +131,4 @@ class PeerConnection {
|
|
|
131
131
|
this.pc.close().catch(util_1.logError);
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
-
exports.
|
|
134
|
+
exports.WeriftPeerConnection = WeriftPeerConnection;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { RingCamera } from '../ring-camera';
|
|
2
|
+
import { StreamingConnectionBase, StreamingConnectionOptions } from './streaming-connection-base';
|
|
3
|
+
interface SessionBody {
|
|
4
|
+
doorbot_id: number;
|
|
5
|
+
session_id: string;
|
|
6
|
+
}
|
|
7
|
+
interface AnswerMessage {
|
|
8
|
+
method: 'sdp';
|
|
9
|
+
body: {
|
|
10
|
+
sdp: string;
|
|
11
|
+
type: 'answer';
|
|
12
|
+
} & SessionBody;
|
|
13
|
+
}
|
|
14
|
+
interface IceCandidateMessage {
|
|
15
|
+
method: 'ice';
|
|
16
|
+
body: {
|
|
17
|
+
ice: string;
|
|
18
|
+
mlineindex: number;
|
|
19
|
+
} & SessionBody;
|
|
20
|
+
}
|
|
21
|
+
interface SessionCreatedMessage {
|
|
22
|
+
method: 'session_created';
|
|
23
|
+
body: SessionBody;
|
|
24
|
+
}
|
|
25
|
+
interface SessionStartedMessage {
|
|
26
|
+
method: 'session_started';
|
|
27
|
+
body: SessionBody;
|
|
28
|
+
}
|
|
29
|
+
interface PongMessage {
|
|
30
|
+
method: 'pong';
|
|
31
|
+
body: SessionBody;
|
|
32
|
+
}
|
|
33
|
+
interface NotificationMessage {
|
|
34
|
+
method: 'notification';
|
|
35
|
+
body: {
|
|
36
|
+
is_ok: boolean;
|
|
37
|
+
text: string;
|
|
38
|
+
} & SessionBody;
|
|
39
|
+
}
|
|
40
|
+
declare enum CloseReasonCode {
|
|
41
|
+
NormalClose = 0,
|
|
42
|
+
AuthenticationFailed = 5,
|
|
43
|
+
Timeout = 6
|
|
44
|
+
}
|
|
45
|
+
interface CloseMessage {
|
|
46
|
+
method: 'close';
|
|
47
|
+
body: {
|
|
48
|
+
reason: {
|
|
49
|
+
code: CloseReasonCode;
|
|
50
|
+
text: string;
|
|
51
|
+
};
|
|
52
|
+
} & SessionBody;
|
|
53
|
+
}
|
|
54
|
+
declare type IncomingMessage = AnswerMessage | IceCandidateMessage | SessionCreatedMessage | SessionStartedMessage | PongMessage | CloseMessage | NotificationMessage;
|
|
55
|
+
export declare class RingEdgeConnection extends StreamingConnectionBase {
|
|
56
|
+
private camera;
|
|
57
|
+
private readonly onSessionId;
|
|
58
|
+
private readonly onOfferSent;
|
|
59
|
+
constructor(authToken: string, camera: RingCamera, options: StreamingConnectionOptions);
|
|
60
|
+
private initiateCall;
|
|
61
|
+
private sessionId;
|
|
62
|
+
protected handleMessage(message: IncomingMessage): Promise<void>;
|
|
63
|
+
protected sendSessionMessage(method: string, body?: Record<any, any>): void;
|
|
64
|
+
}
|
|
65
|
+
export {};
|