homebridge-ring 11.0.7 → 11.1.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 +15 -0
- package/README.md +1 -0
- package/config.schema.json +8 -6
- package/lib/homebridge/camera-source.d.ts +2 -1
- package/lib/homebridge/camera-source.js +99 -29
- package/lib/homebridge/camera.js +1 -1
- package/lib/homebridge/config.d.ts +3 -2
- package/lib/homebridge/homebridge-ui/public/asset-manifest.json +10 -10
- package/lib/homebridge/homebridge-ui/public/index.html +1 -1
- package/lib/homebridge/homebridge-ui/public/static/js/2.2785c6d1.chunk.js +3 -0
- package/lib/homebridge/homebridge-ui/public/static/js/{2.fe3feb44.chunk.js.LICENSE.txt → 2.2785c6d1.chunk.js.LICENSE.txt} +0 -0
- package/lib/homebridge/homebridge-ui/public/static/js/2.2785c6d1.chunk.js.map +1 -0
- package/lib/homebridge/homebridge-ui/public/static/js/{main.adeecae1.chunk.js → main.3d6c9caf.chunk.js} +1 -1
- package/lib/homebridge/homebridge-ui/public/static/js/main.3d6c9caf.chunk.js.map +1 -0
- package/lib/homebridge/homebridge-ui/public/static/js/{runtime-main.401a8c6e.js → runtime-main.6cce355a.js} +1 -1
- package/lib/homebridge/homebridge-ui/public/static/js/runtime-main.6cce355a.js.map +1 -0
- package/lib/homebridge/opus-repacketizer.d.ts +7 -0
- package/lib/homebridge/opus-repacketizer.js +87 -0
- package/lib/homebridge/ring-platform.js +23 -5
- package/package.json +16 -16
- package/lib/homebridge/homebridge-ui/public/static/js/2.fe3feb44.chunk.js +0 -3
- package/lib/homebridge/homebridge-ui/public/static/js/2.fe3feb44.chunk.js.map +0 -1
- package/lib/homebridge/homebridge-ui/public/static/js/main.adeecae1.chunk.js.map +0 -1
- package/lib/homebridge/homebridge-ui/public/static/js/runtime-main.401a8c6e.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
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
|
+
## [11.1.0](https://github.com/dgreif/ring/compare/v11.0.7...v11.1.0) (2022-08-21)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **homebridge:** allow cameras to be unbridged ([7302298](https://github.com/dgreif/ring/commit/73022983eed59e6af4bfdf0d8f1ee9d8ee8f6953))
|
|
11
|
+
* **homebridge:** use opus transcoding for unbridge cameras ([e9eb7a4](https://github.com/dgreif/ring/commit/e9eb7a4940ce7d01dee920593af3bdd12e25fa1a))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **homebridge:** add unbridgeCameras option to ui schema ([e97047d](https://github.com/dgreif/ring/commit/e97047df7d959caee95f958a3a6aed5537f93f58))
|
|
17
|
+
* update dependencies ([20584cd](https://github.com/dgreif/ring/commit/20584cdb6fe3d9fa9fd598a1bec612cfe37e3e82))
|
|
18
|
+
* update dependencies ([6f98cdf](https://github.com/dgreif/ring/commit/6f98cdf48895daf3217890b6631a6dbb2ccd340f))
|
|
19
|
+
|
|
5
20
|
### [11.0.7](https://github.com/dgreif/ring/compare/v11.0.6...v11.0.7) (2022-07-10)
|
|
6
21
|
|
|
7
22
|
|
package/README.md
CHANGED
|
@@ -72,6 +72,7 @@ Only include an optional parameter if you actually need it. Default behavior wi
|
|
|
72
72
|
|
|
73
73
|
| Option | Default | Explanation |
|
|
74
74
|
| ---------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `unbridgeCameras` | `false` | if `true`, all Ring Cameras we be treated as external accessories, which generally leads to better performance. This means they each need to be individually added to HomeKit. WARNING: If your cameras are already bridged, they will be deleted from HomeKit when you enable this option, and you will need to reconfigure any associated automations or HomeKit settings |
|
|
75
76
|
| `alarmOnEntryDelay` | `false` | if `true`, HomeKit will register a delayed entry event as a triggered alarm. There are some households where this is a nice feature as a heads up if you have other people who enter your house and you want an alert so that you can disable the alarm for them before it actually goes off. This works well if you automatically arm/disarm on leave/arrive (see setup instructions below) |
|
|
76
77
|
| `beamDurationSeconds` | `60` for light groups, previous from Ring app for individual lights | Ring smart lighting has a default behavior of only staying on for 60 seconds when you turn on a light via the Ring app. To force a duration when the light is turned on from HomeKit, set this option to a specific number of seconds. If this option is not set, the lights will use the duration from the previous time the light was turned on in the Ring app. For light groups, this will default to 60 seconds. The maximum value is `32767`, which is ~9.1 hours. |
|
|
77
78
|
| `hideDeviceIds` | `[]` | Allows you to hide specific devices by an array of ids. The id for each device is logged when homebridge starts. |
|
package/config.schema.json
CHANGED
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"description": "Click \"Generate New Refresh Token\" above to change accounts or if your refresh token has expired",
|
|
17
17
|
"placeholder": "Refresh Token"
|
|
18
18
|
},
|
|
19
|
+
"unbridgeCameras": {
|
|
20
|
+
"title": "Unbridge Cameras",
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"description": "If enabled, all Ring Cameras we be treated as external accessories, which generally leads to better performance. This means they each need to be individually added to HomeKit. WARNING: If your cameras are already bridged, they will be deleted from HomeKit when you enable this option, and you will need to reconfigure any associated automations or HomeKit settings"
|
|
23
|
+
},
|
|
19
24
|
"alarmOnEntryDelay": {
|
|
20
25
|
"title": "Alarm on Entry Delay",
|
|
21
26
|
"type": "boolean",
|
|
@@ -74,15 +79,11 @@
|
|
|
74
79
|
"oneOf": [
|
|
75
80
|
{
|
|
76
81
|
"title": "Home",
|
|
77
|
-
"enum": [
|
|
78
|
-
"some"
|
|
79
|
-
]
|
|
82
|
+
"enum": ["some"]
|
|
80
83
|
},
|
|
81
84
|
{
|
|
82
85
|
"title": "Away",
|
|
83
|
-
"enum": [
|
|
84
|
-
"all"
|
|
85
|
-
]
|
|
86
|
+
"enum": ["all"]
|
|
86
87
|
}
|
|
87
88
|
]
|
|
88
89
|
},
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
"title": "Optional Configuration",
|
|
157
158
|
"expandable": true,
|
|
158
159
|
"items": [
|
|
160
|
+
"unbridgeCameras",
|
|
159
161
|
"alarmOnEntryDelay",
|
|
160
162
|
"hideLightGroups",
|
|
161
163
|
"hideDoorbellSwitch",
|
|
@@ -2,10 +2,11 @@ import { RingCamera } from '../api';
|
|
|
2
2
|
import { CameraStreamingDelegate, PrepareStreamCallback, PrepareStreamRequest, SnapshotRequest, SnapshotRequestCallback, StreamingRequest, StreamRequestCallback } from 'homebridge';
|
|
3
3
|
export declare class CameraSource implements CameraStreamingDelegate {
|
|
4
4
|
private ringCamera;
|
|
5
|
+
private useOpus;
|
|
5
6
|
controller: import("homebridge").CameraController;
|
|
6
7
|
private sessions;
|
|
7
8
|
private cachedSnapshot?;
|
|
8
|
-
constructor(ringCamera: RingCamera);
|
|
9
|
+
constructor(ringCamera: RingCamera, useOpus?: boolean);
|
|
9
10
|
private previousLoadSnapshotPromise?;
|
|
10
11
|
loadSnapshot(imageUuid?: string): Promise<any>;
|
|
11
12
|
fn: number;
|
|
@@ -10,6 +10,7 @@ const fs_1 = require("fs");
|
|
|
10
10
|
const util_2 = require("util");
|
|
11
11
|
const ffmpeg_1 = require("../api/ffmpeg");
|
|
12
12
|
const werift_1 = require("werift");
|
|
13
|
+
const opus_repacketizer_1 = require("./opus-repacketizer");
|
|
13
14
|
const readFileAsync = (0, util_2.promisify)(fs_1.readFile), cameraOfflinePath = require.resolve('../../media/camera-offline.jpg'), snapshotsBlockedPath = require.resolve('../../media/snapshots-blocked.jpg');
|
|
14
15
|
function getDurationSeconds(start) {
|
|
15
16
|
return (Date.now() - start) / 1000;
|
|
@@ -37,6 +38,7 @@ class StreamingSessionWrapper {
|
|
|
37
38
|
this.videoSrtp = (0, camera_utils_1.generateSrtpOptions)();
|
|
38
39
|
this.audioSplitter = new camera_utils_1.RtpSplitter();
|
|
39
40
|
this.videoSplitter = new camera_utils_1.RtpSplitter();
|
|
41
|
+
this.repacketizeAudioSplitter = new camera_utils_1.RtpSplitter();
|
|
40
42
|
this.libfdkAacInstalledPromise = (0, camera_utils_1.doesFfmpegSupportCodec)('libfdk_aac', (0, ffmpeg_1.getFfmpegPath)())
|
|
41
43
|
.then((supported) => {
|
|
42
44
|
if (!supported) {
|
|
@@ -89,9 +91,57 @@ class StreamingSessionWrapper {
|
|
|
89
91
|
.catch(util_1.logError);
|
|
90
92
|
}));
|
|
91
93
|
}
|
|
94
|
+
listenForAudioPackets(startStreamRequest) {
|
|
95
|
+
const { targetAddress, audio: { port: audioPort }, } = this.prepareStreamRequest, { audio: { codec: audioCodec, sample_rate: audioSampleRate }, } = startStreamRequest,
|
|
96
|
+
// Repacketize the audio stream after it's been transcoded
|
|
97
|
+
opusRepacketizer = new opus_repacketizer_1.OpusRepacketizer(1), audioIntervalScale = audioSampleRate / 8, audioSrtpSession = new werift_1.SrtpSession(getSessionConfig(this.audioSrtp));
|
|
98
|
+
let firstTimestamp, audioPacketCount = 0;
|
|
99
|
+
this.repacketizeAudioSplitter.addMessageHandler(({ message }) => {
|
|
100
|
+
let rtp = werift_1.RtpPacket.deSerialize(message);
|
|
101
|
+
if (audioCodec === "OPUS" /* AudioStreamingCodecType.OPUS */) {
|
|
102
|
+
// borrowed from scrypted
|
|
103
|
+
// Original source: https://github.com/koush/scrypted/blob/c13ba09889c3e0d9d3724cb7d49253c9d787fb97/plugins/homekit/src/types/camera/camera-streaming-srtp-sender.ts#L124-L143
|
|
104
|
+
rtp = opusRepacketizer.repacketize(werift_1.RtpPacket.deSerialize(message));
|
|
105
|
+
if (!rtp) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
if (!firstTimestamp) {
|
|
109
|
+
firstTimestamp = rtp.header.timestamp;
|
|
110
|
+
}
|
|
111
|
+
// from HAP spec:
|
|
112
|
+
// RTP Payload Format for Opus Speech and Audio Codec RFC 7587 with an exception
|
|
113
|
+
// that Opus audio RTP Timestamp shall be based on RFC 3550.
|
|
114
|
+
// RFC 3550 indicates that PCM audio based with a sample rate of 8k and a packet
|
|
115
|
+
// time of 20ms would have a monotonic interval of 8k / (1000 / 20) = 160.
|
|
116
|
+
// So 24k audio would have a monotonic interval of (24k / 8k) * 160 = 480.
|
|
117
|
+
// HAP spec also states that it may request packet times of 20, 30, 40, or 60.
|
|
118
|
+
// In practice, HAP has been seen to request 20 on LAN and 60 over LTE.
|
|
119
|
+
// So the RTP timestamp must scale accordingly.
|
|
120
|
+
// Further investigation indicates that HAP doesn't care about the actual sample rate at all,
|
|
121
|
+
// that's merely a suggestion. When encoding Opus, it can seemingly be an arbitrary sample rate,
|
|
122
|
+
// audio will work so long as the rtp timestamps are created properly: which is a construct of the sample rate
|
|
123
|
+
// HAP requests, and the packet time is respected,
|
|
124
|
+
// opus 48khz will work just fine.
|
|
125
|
+
rtp.header.timestamp =
|
|
126
|
+
(firstTimestamp + audioPacketCount * 180 * audioIntervalScale) %
|
|
127
|
+
0xffffffff;
|
|
128
|
+
audioPacketCount++;
|
|
129
|
+
}
|
|
130
|
+
// encrypt the packet
|
|
131
|
+
const encryptedPacket = audioSrtpSession.encrypt(rtp.payload, rtp.header);
|
|
132
|
+
// send the encrypted packet to HomeKit
|
|
133
|
+
this.audioSplitter
|
|
134
|
+
.send(encryptedPacket, {
|
|
135
|
+
port: audioPort,
|
|
136
|
+
address: targetAddress,
|
|
137
|
+
})
|
|
138
|
+
.catch(util_1.logError);
|
|
139
|
+
return null;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
92
142
|
async activate(request) {
|
|
93
143
|
let sentVideo = false;
|
|
94
|
-
const { targetAddress, audio: {
|
|
144
|
+
const { targetAddress, audio: { srtp_key: remoteAudioSrtpKey, srtp_salt: remoteAudioSrtpSalt }, video: { port: videoPort }, } = this.prepareStreamRequest,
|
|
95
145
|
// use to encrypt Ring video to HomeKit
|
|
96
146
|
videoSrtpSession = new werift_1.SrtpSession(getSessionConfig(this.videoSrtp));
|
|
97
147
|
// Set up packet forwarding for video stream
|
|
@@ -119,20 +169,23 @@ class StreamingSessionWrapper {
|
|
|
119
169
|
audio: [
|
|
120
170
|
'-map',
|
|
121
171
|
'0:a',
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
172
|
+
...(request.audio.codec === "OPUS" /* AudioStreamingCodecType.OPUS */
|
|
173
|
+
? [
|
|
174
|
+
// OPUS specific - it works, but audio is very choppy
|
|
175
|
+
'-acodec',
|
|
176
|
+
'libopus',
|
|
177
|
+
'-frame_duration',
|
|
178
|
+
request.audio.packet_time,
|
|
179
|
+
'-application',
|
|
180
|
+
'lowdelay',
|
|
181
|
+
]
|
|
182
|
+
: [
|
|
183
|
+
// AAC-eld specific
|
|
184
|
+
'-acodec',
|
|
185
|
+
'libfdk_aac',
|
|
186
|
+
'-profile:a',
|
|
187
|
+
'aac_eld',
|
|
188
|
+
]),
|
|
136
189
|
// Shared options
|
|
137
190
|
'-flags',
|
|
138
191
|
'+global_header',
|
|
@@ -150,11 +203,8 @@ class StreamingSessionWrapper {
|
|
|
150
203
|
this.audioSsrc,
|
|
151
204
|
'-f',
|
|
152
205
|
'rtp',
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
'-srtp_out_params',
|
|
156
|
-
(0, camera_utils_1.encodeSrtpOptions)(this.audioSrtp),
|
|
157
|
-
`srtp://${targetAddress}:${audioPort}?pkt_size=188`,
|
|
206
|
+
`rtp://127.0.0.1:${await this.repacketizeAudioSplitter
|
|
207
|
+
.portPromise}?pkt_size=188`,
|
|
158
208
|
],
|
|
159
209
|
video: false,
|
|
160
210
|
output: [],
|
|
@@ -180,15 +230,16 @@ class StreamingSessionWrapper {
|
|
|
180
230
|
// deSerialize will sometimes fail, but the errors can be ignored
|
|
181
231
|
}
|
|
182
232
|
return null;
|
|
183
|
-
}),
|
|
233
|
+
}), isRingUsingOpus = await this.streamingSession.isUsingOpus, returnAudioTranscoder = new camera_utils_1.ReturnAudioTranscoder({
|
|
184
234
|
prepareStreamRequest: this.prepareStreamRequest,
|
|
235
|
+
startStreamRequest: request,
|
|
185
236
|
incomingAudioOptions: {
|
|
186
237
|
ssrc: this.audioSsrc,
|
|
187
238
|
rtcpPort: 0, // we don't care about rtcp for incoming audio
|
|
188
239
|
},
|
|
189
240
|
outputArgs: [
|
|
190
241
|
'-acodec',
|
|
191
|
-
...(
|
|
242
|
+
...(isRingUsingOpus
|
|
192
243
|
? ['libopus', '-ac', 2, '-ar', '48k']
|
|
193
244
|
: ['pcm_mulaw', '-ac', 1, '-ar', '8k']),
|
|
194
245
|
'-flags',
|
|
@@ -209,18 +260,21 @@ class StreamingSessionWrapper {
|
|
|
209
260
|
returnAudioTranscoder.stop();
|
|
210
261
|
returnAudioTranscodedSplitter.close();
|
|
211
262
|
});
|
|
263
|
+
this.listenForAudioPackets(request);
|
|
212
264
|
await returnAudioTranscoder.start();
|
|
213
265
|
await transcodingPromise;
|
|
214
266
|
}
|
|
215
267
|
stop() {
|
|
216
268
|
this.audioSplitter.close();
|
|
269
|
+
this.repacketizeAudioSplitter.close();
|
|
217
270
|
this.videoSplitter.close();
|
|
218
271
|
this.streamingSession.stop();
|
|
219
272
|
}
|
|
220
273
|
}
|
|
221
274
|
class CameraSource {
|
|
222
|
-
constructor(ringCamera) {
|
|
275
|
+
constructor(ringCamera, useOpus = false) {
|
|
223
276
|
this.ringCamera = ringCamera;
|
|
277
|
+
this.useOpus = useOpus;
|
|
224
278
|
this.controller = new hap_1.hap.CameraController({
|
|
225
279
|
cameraStreamCount: 10,
|
|
226
280
|
delegate: this,
|
|
@@ -244,12 +298,28 @@ class CameraSource {
|
|
|
244
298
|
},
|
|
245
299
|
},
|
|
246
300
|
audio: {
|
|
247
|
-
codecs:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
301
|
+
codecs: this.useOpus
|
|
302
|
+
? [
|
|
303
|
+
{
|
|
304
|
+
type: "OPUS" /* AudioStreamingCodecType.OPUS */,
|
|
305
|
+
// required by watch
|
|
306
|
+
samplerate: 8 /* AudioStreamingSamplerate.KHZ_8 */,
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
type: "OPUS" /* AudioStreamingCodecType.OPUS */,
|
|
310
|
+
samplerate: 16 /* AudioStreamingSamplerate.KHZ_16 */,
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
type: "OPUS" /* AudioStreamingCodecType.OPUS */,
|
|
314
|
+
samplerate: 24 /* AudioStreamingSamplerate.KHZ_24 */,
|
|
315
|
+
},
|
|
316
|
+
]
|
|
317
|
+
: [
|
|
318
|
+
{
|
|
319
|
+
type: "AAC-eld" /* AudioStreamingCodecType.AAC_ELD */,
|
|
320
|
+
samplerate: 16 /* AudioStreamingSamplerate.KHZ_16 */,
|
|
321
|
+
},
|
|
322
|
+
],
|
|
253
323
|
},
|
|
254
324
|
},
|
|
255
325
|
});
|
package/lib/homebridge/camera.js
CHANGED
|
@@ -13,7 +13,7 @@ class Camera extends base_data_accessory_1.BaseDataAccessory {
|
|
|
13
13
|
this.accessory = accessory;
|
|
14
14
|
this.logger = logger;
|
|
15
15
|
this.config = config;
|
|
16
|
-
this.cameraSource = new camera_source_1.CameraSource(this.device);
|
|
16
|
+
this.cameraSource = new camera_source_1.CameraSource(this.device, this.config.unbridgeCameras);
|
|
17
17
|
if (!hap_1.hap.CameraController) {
|
|
18
18
|
const error = 'HAP CameraController not found. Please make sure you are on homebridge version 1.0.0 or newer';
|
|
19
19
|
logger.error(error);
|
|
@@ -3,6 +3,7 @@ import { API } from 'homebridge';
|
|
|
3
3
|
export interface RingPlatformConfig extends RingApiOptions {
|
|
4
4
|
alarmOnEntryDelay?: boolean;
|
|
5
5
|
beamDurationSeconds?: number;
|
|
6
|
+
ffmpegPath?: string;
|
|
6
7
|
hideLightGroups?: boolean;
|
|
7
8
|
hideDoorbellSwitch?: boolean;
|
|
8
9
|
hideCameraLight?: boolean;
|
|
@@ -12,10 +13,10 @@ export interface RingPlatformConfig extends RingApiOptions {
|
|
|
12
13
|
hideAlarmSirenSwitch?: boolean;
|
|
13
14
|
hideUnsupportedServices?: boolean;
|
|
14
15
|
hideDeviceIds?: string[];
|
|
16
|
+
nightModeBypassFor: AlarmMode;
|
|
15
17
|
onlyDeviceTypes?: string[];
|
|
16
18
|
showPanicButtons?: boolean;
|
|
17
|
-
|
|
18
|
-
ffmpegPath?: string;
|
|
19
|
+
unbridgeCameras?: boolean;
|
|
19
20
|
}
|
|
20
21
|
export declare function updateHomebridgeConfig(homebridge: API, update: (config: string) => string): boolean;
|
|
21
22
|
export declare function getSystemId(homebridge: API): string;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
|
-
"main.js": "./static/js/main.
|
|
4
|
-
"main.js.map": "./static/js/main.
|
|
5
|
-
"runtime-main.js": "./static/js/runtime-main.
|
|
6
|
-
"runtime-main.js.map": "./static/js/runtime-main.
|
|
7
|
-
"static/js/2.
|
|
8
|
-
"static/js/2.
|
|
3
|
+
"main.js": "./static/js/main.3d6c9caf.chunk.js",
|
|
4
|
+
"main.js.map": "./static/js/main.3d6c9caf.chunk.js.map",
|
|
5
|
+
"runtime-main.js": "./static/js/runtime-main.6cce355a.js",
|
|
6
|
+
"runtime-main.js.map": "./static/js/runtime-main.6cce355a.js.map",
|
|
7
|
+
"static/js/2.2785c6d1.chunk.js": "./static/js/2.2785c6d1.chunk.js",
|
|
8
|
+
"static/js/2.2785c6d1.chunk.js.map": "./static/js/2.2785c6d1.chunk.js.map",
|
|
9
9
|
"index.html": "./index.html",
|
|
10
|
-
"static/js/2.
|
|
10
|
+
"static/js/2.2785c6d1.chunk.js.LICENSE.txt": "./static/js/2.2785c6d1.chunk.js.LICENSE.txt"
|
|
11
11
|
},
|
|
12
12
|
"entrypoints": [
|
|
13
|
-
"static/js/runtime-main.
|
|
14
|
-
"static/js/2.
|
|
15
|
-
"static/js/main.
|
|
13
|
+
"static/js/runtime-main.6cce355a.js",
|
|
14
|
+
"static/js/2.2785c6d1.chunk.js",
|
|
15
|
+
"static/js/main.3d6c9caf.chunk.js"
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<div id="root"></div><script>!function(e){function r(r){for(var n,i,l=r[0],f=r[1],a=r[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var f=t[l];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./";var l=this["webpackJsonphomebridge-ui"]=this["webpackJsonphomebridge-ui"]||[],f=l.push.bind(l);l.push=r,l=l.slice();for(var a=0;a<l.length;a++)r(l[a]);var p=f;t()}([])</script><script src="./static/js/2.
|
|
1
|
+
<div id="root"></div><script>!function(e){function r(r){for(var n,i,l=r[0],f=r[1],a=r[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var f=t[l];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./";var l=this["webpackJsonphomebridge-ui"]=this["webpackJsonphomebridge-ui"]||[],f=l.push.bind(l);l.push=r,l=l.slice();for(var a=0;a<l.length;a++)r(l[a]);var p=f;t()}([])</script><script src="./static/js/2.2785c6d1.chunk.js"></script><script src="./static/js/main.3d6c9caf.chunk.js"></script>
|