homebridge-eufy-security 4.4.2-beta.2 → 4.4.2-beta.20
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 +1 -1
- package/FUNDING.yml +1 -0
- package/README.md +14 -17
- package/dist/accessories/AutoSyncStationAccessory.js +26 -30
- package/dist/accessories/AutoSyncStationAccessory.js.map +1 -1
- package/dist/accessories/BaseAccessory.js +33 -46
- package/dist/accessories/BaseAccessory.js.map +1 -1
- package/dist/accessories/CameraAccessory.js +92 -167
- package/dist/accessories/CameraAccessory.js.map +1 -1
- package/dist/accessories/Device.js +11 -15
- package/dist/accessories/Device.js.map +1 -1
- package/dist/accessories/EntrySensorAccessory.js +7 -12
- package/dist/accessories/EntrySensorAccessory.js.map +1 -1
- package/dist/accessories/LockAccessory.js +20 -24
- package/dist/accessories/LockAccessory.js.map +1 -1
- package/dist/accessories/MotionSensorAccessory.js +7 -12
- package/dist/accessories/MotionSensorAccessory.js.map +1 -1
- package/dist/accessories/StationAccessory.js +40 -45
- package/dist/accessories/StationAccessory.js.map +1 -1
- package/dist/config.js +1 -4
- package/dist/config.js.map +1 -1
- package/dist/controller/LocalLivestreamManager.js +85 -89
- package/dist/controller/LocalLivestreamManager.js.map +1 -1
- package/dist/controller/recordingDelegate.js +116 -108
- package/dist/controller/recordingDelegate.js.map +1 -1
- package/dist/controller/snapshotDelegate.js +379 -0
- package/dist/controller/snapshotDelegate.js.map +1 -0
- package/dist/controller/streamingDelegate.js +202 -207
- package/dist/controller/streamingDelegate.js.map +1 -1
- package/dist/index.js +9 -7
- package/dist/index.js.map +1 -1
- package/dist/interfaces.js +1 -2
- package/dist/interfaces.js.map +1 -1
- package/dist/platform.js +145 -165
- package/dist/platform.js.map +1 -1
- package/dist/settings.js +26 -19
- package/dist/settings.js.map +1 -1
- package/dist/utils/Talkback.js +9 -13
- package/dist/utils/Talkback.js.map +1 -1
- package/dist/utils/configTypes.js +12 -7
- package/dist/utils/configTypes.js.map +1 -1
- package/dist/utils/ffmpeg.js +44 -52
- package/dist/utils/ffmpeg.js.map +1 -1
- package/dist/utils/interfaces.js +1 -5
- package/dist/utils/interfaces.js.map +1 -1
- package/dist/utils/utils.js +32 -134
- package/dist/utils/utils.js.map +1 -1
- package/dist/version.js +1 -4
- package/dist/version.js.map +1 -1
- package/eslint.config.mjs +25 -47
- package/homebridge-eufy-security.png +0 -0
- package/homebridge-ui/public/app.js +221 -0
- package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebasemini_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
- package/homebridge-ui/public/components/device-card.js +141 -0
- package/homebridge-ui/public/components/guard-modes.js +88 -0
- package/homebridge-ui/public/components/number-input.js +121 -0
- package/homebridge-ui/public/components/select.js +73 -0
- package/homebridge-ui/public/components/toggle.js +68 -0
- package/homebridge-ui/public/index.html +24 -14
- package/homebridge-ui/public/services/api.js +129 -0
- package/homebridge-ui/public/services/config.js +144 -0
- package/homebridge-ui/public/style.css +705 -0
- package/homebridge-ui/public/utils/countries.js +73 -0
- package/homebridge-ui/public/utils/device-images.js +69 -0
- package/homebridge-ui/public/utils/helpers.js +47 -0
- package/homebridge-ui/public/views/dashboard.js +211 -0
- package/homebridge-ui/public/views/device-detail.js +631 -0
- package/homebridge-ui/public/views/login.js +625 -0
- package/homebridge-ui/public/views/settings.js +389 -0
- package/homebridge-ui/public/views/unsupported-detail.js +216 -0
- package/homebridge-ui/server.js +567 -450
- package/package.json +19 -59
- package/dist/accessories/AutoSyncStationAccessory.d.ts +0 -42
- package/dist/accessories/AutoSyncStationAccessory.d.ts.map +0 -1
- package/dist/accessories/BaseAccessory.d.ts +0 -56
- package/dist/accessories/BaseAccessory.d.ts.map +0 -1
- package/dist/accessories/CameraAccessory.d.ts +0 -84
- package/dist/accessories/CameraAccessory.d.ts.map +0 -1
- package/dist/accessories/Device.d.ts +0 -19
- package/dist/accessories/Device.d.ts.map +0 -1
- package/dist/accessories/EntrySensorAccessory.d.ts +0 -25
- package/dist/accessories/EntrySensorAccessory.d.ts.map +0 -1
- package/dist/accessories/LockAccessory.d.ts +0 -45
- package/dist/accessories/LockAccessory.d.ts.map +0 -1
- package/dist/accessories/MotionSensorAccessory.d.ts +0 -25
- package/dist/accessories/MotionSensorAccessory.d.ts.map +0 -1
- package/dist/accessories/StationAccessory.d.ts +0 -86
- package/dist/accessories/StationAccessory.d.ts.map +0 -1
- package/dist/config.d.ts +0 -31
- package/dist/config.d.ts.map +0 -1
- package/dist/controller/LocalLivestreamManager.d.ts +0 -31
- package/dist/controller/LocalLivestreamManager.d.ts.map +0 -1
- package/dist/controller/SnapshotManager.d.ts +0 -64
- package/dist/controller/SnapshotManager.d.ts.map +0 -1
- package/dist/controller/SnapshotManager.js +0 -434
- package/dist/controller/SnapshotManager.js.map +0 -1
- package/dist/controller/recordingDelegate.d.ts +0 -27
- package/dist/controller/recordingDelegate.d.ts.map +0 -1
- package/dist/controller/streamingDelegate.d.ts +0 -52
- package/dist/controller/streamingDelegate.d.ts.map +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/interfaces.d.ts +0 -15
- package/dist/interfaces.d.ts.map +0 -1
- package/dist/platform.d.ts +0 -94
- package/dist/platform.d.ts.map +0 -1
- package/dist/settings.d.ts +0 -23
- package/dist/settings.d.ts.map +0 -1
- package/dist/utils/Talkback.d.ts +0 -21
- package/dist/utils/Talkback.d.ts.map +0 -1
- package/dist/utils/configTypes.d.ts +0 -68
- package/dist/utils/configTypes.d.ts.map +0 -1
- package/dist/utils/ffmpeg.d.ts +0 -111
- package/dist/utils/ffmpeg.d.ts.map +0 -1
- package/dist/utils/interfaces.d.ts +0 -8
- package/dist/utils/interfaces.d.ts.map +0 -1
- package/dist/utils/utils.d.ts +0 -35
- package/dist/utils/utils.d.ts.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
- package/homebridge-ui/configui/app/util/types.d.ts +0 -65
- package/homebridge-ui/configui/app/util/types.d.ts.map +0 -1
- package/homebridge-ui/configui/app/util/types.js +0 -18
- package/homebridge-ui/configui/app/util/types.js.map +0 -1
- package/homebridge-ui/public/3rdpartylicenses.txt +0 -561
- package/homebridge-ui/public/assets/devices/homebase2_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/homebase3_large.jpg +0 -0
- package/homebridge-ui/public/assets/images/homebridge-eufy-security.png +0 -0
- package/homebridge-ui/public/favicon.ico +0 -0
- package/homebridge-ui/public/main.f6423287e0411c87.js +0 -1
- package/homebridge-ui/public/polyfills.efa2f09ba3e49167.js +0 -1
- package/homebridge-ui/public/runtime.ccde331d62c423b3.js +0 -1
- package/homebridge-ui/public/styles.13e635bf7a488639.css +0 -5
- package/homebridge-ui/server.d.ts +0 -2
- package/homebridge-ui/server.d.ts.map +0 -1
- package/homebridge-ui/server.js.map +0 -1
- package/homebridge-ui/version.d.ts +0 -2
- package/homebridge-ui/version.d.ts.map +0 -1
- package/homebridge-ui/version.js +0 -5
- package/homebridge-ui/version.js.map +0 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toggle component — renders an on/off switch with label and optional help tooltip.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* Toggle.render(container, {
|
|
6
|
+
* id: 'enable-camera',
|
|
7
|
+
* label: 'Enable Camera',
|
|
8
|
+
* help: 'Show this camera in HomeKit',
|
|
9
|
+
* checked: true,
|
|
10
|
+
* onChange: (checked) => { ... }
|
|
11
|
+
* });
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line no-unused-vars
|
|
14
|
+
const Toggle = {
|
|
15
|
+
/**
|
|
16
|
+
* @param {HTMLElement} container - parent element to append into
|
|
17
|
+
* @param {object} opts
|
|
18
|
+
* @param {string} opts.id - unique id for the input
|
|
19
|
+
* @param {string} opts.label - display label
|
|
20
|
+
* @param {string} [opts.help] - tooltip text
|
|
21
|
+
* @param {boolean} opts.checked - initial state
|
|
22
|
+
* @param {boolean} [opts.disabled] - disabled state
|
|
23
|
+
* @param {function} opts.onChange - callback(checked: boolean)
|
|
24
|
+
* @returns {HTMLElement}
|
|
25
|
+
*/
|
|
26
|
+
render(container, opts) {
|
|
27
|
+
const row = document.createElement('div');
|
|
28
|
+
row.className = 'eufy-toggle';
|
|
29
|
+
|
|
30
|
+
const labelWrap = document.createElement('div');
|
|
31
|
+
labelWrap.className = 'eufy-toggle__label';
|
|
32
|
+
|
|
33
|
+
const labelEl = document.createElement('label');
|
|
34
|
+
labelEl.setAttribute('for', opts.id);
|
|
35
|
+
labelEl.textContent = opts.label;
|
|
36
|
+
labelWrap.appendChild(labelEl);
|
|
37
|
+
|
|
38
|
+
if (opts.help) {
|
|
39
|
+
const helpEl = document.createElement('span');
|
|
40
|
+
helpEl.className = 'eufy-toggle__help';
|
|
41
|
+
helpEl.textContent = '?';
|
|
42
|
+
helpEl.title = opts.help;
|
|
43
|
+
labelWrap.appendChild(helpEl);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const switchWrap = document.createElement('div');
|
|
47
|
+
switchWrap.className = 'form-check form-switch mb-0';
|
|
48
|
+
|
|
49
|
+
const input = document.createElement('input');
|
|
50
|
+
input.type = 'checkbox';
|
|
51
|
+
input.className = 'form-check-input';
|
|
52
|
+
input.id = opts.id;
|
|
53
|
+
input.checked = !!opts.checked;
|
|
54
|
+
input.disabled = !!opts.disabled;
|
|
55
|
+
input.role = 'switch';
|
|
56
|
+
|
|
57
|
+
input.addEventListener('change', () => {
|
|
58
|
+
if (opts.onChange) opts.onChange(input.checked);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
switchWrap.appendChild(input);
|
|
62
|
+
row.appendChild(labelWrap);
|
|
63
|
+
row.appendChild(switchWrap);
|
|
64
|
+
|
|
65
|
+
if (container) container.appendChild(row);
|
|
66
|
+
return row;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
<html lang="en">
|
|
1
|
+
<link rel="stylesheet" href="style.css">
|
|
3
2
|
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
<div id="app">
|
|
4
|
+
<div class="d-flex justify-content-center align-items-center" style="min-height: 200px;">
|
|
5
|
+
<div class="spinner-border text-primary" role="status">
|
|
6
|
+
<span class="visually-hidden">Loading...</span>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
11
10
|
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
<script src="
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
<script src="utils/countries.js"></script>
|
|
12
|
+
<script src="utils/device-images.js"></script>
|
|
13
|
+
<script src="utils/helpers.js"></script>
|
|
14
|
+
<script src="services/api.js"></script>
|
|
15
|
+
<script src="services/config.js"></script>
|
|
16
|
+
<script src="components/toggle.js"></script>
|
|
17
|
+
<script src="components/select.js"></script>
|
|
18
|
+
<script src="components/number-input.js"></script>
|
|
19
|
+
<script src="components/guard-modes.js"></script>
|
|
20
|
+
<script src="components/device-card.js"></script>
|
|
21
|
+
<script src="views/login.js"></script>
|
|
22
|
+
<script src="views/dashboard.js"></script>
|
|
23
|
+
<script src="views/device-detail.js"></script>
|
|
24
|
+
<script src="views/unsupported-detail.js"></script>
|
|
25
|
+
<script src="views/settings.js"></script>
|
|
26
|
+
<script src="app.js"></script>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API service — wraps homebridge.request() and push event listeners.
|
|
3
|
+
* Communicates with server.ts endpoints.
|
|
4
|
+
*/
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
const Api = {
|
|
7
|
+
/** @private Track registered listeners to prevent stacking on re-render */
|
|
8
|
+
_listeners: {},
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Register an event listener, replacing any previous listener for the same event.
|
|
12
|
+
* Prevents listener stacking when views re-render.
|
|
13
|
+
* @param {string} event
|
|
14
|
+
* @param {function} handler
|
|
15
|
+
*/
|
|
16
|
+
_on(event, handler) {
|
|
17
|
+
if (this._listeners[event]) {
|
|
18
|
+
homebridge.removeEventListener(event, this._listeners[event]);
|
|
19
|
+
}
|
|
20
|
+
this._listeners[event] = handler;
|
|
21
|
+
homebridge.addEventListener(event, handler);
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Remove a previously registered listener for an event.
|
|
26
|
+
* Views can call this on teardown to explicitly detach their callbacks.
|
|
27
|
+
* @param {string} event
|
|
28
|
+
*/
|
|
29
|
+
_off(event) {
|
|
30
|
+
if (this._listeners[event]) {
|
|
31
|
+
homebridge.removeEventListener(event, this._listeners[event]);
|
|
32
|
+
delete this._listeners[event];
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Login with credentials, TFA code, or captcha
|
|
38
|
+
* @param {object} options - { username, password, country, deviceName } | { verifyCode } | { captcha: { captchaCode, captchaId } }
|
|
39
|
+
* @returns {Promise<{success: boolean, failReason?: number, data?: any}>}
|
|
40
|
+
*/
|
|
41
|
+
async login(options) {
|
|
42
|
+
return homebridge.request('/login', options);
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if a valid persistent cache file exists on the server.
|
|
47
|
+
* @returns {Promise<{valid: boolean}>}
|
|
48
|
+
*/
|
|
49
|
+
async checkCache() {
|
|
50
|
+
return homebridge.request('/checkCache');
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Load stored accessories from server (cached from last login)
|
|
55
|
+
* @returns {Promise<Array>} Array of L_Station objects
|
|
56
|
+
*/
|
|
57
|
+
async loadStoredAccessories() {
|
|
58
|
+
return homebridge.request('/storedAccessories');
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Reset plugin data (removes persistent storage)
|
|
63
|
+
* @returns {Promise<{result: number}>}
|
|
64
|
+
*/
|
|
65
|
+
async resetPlugin() {
|
|
66
|
+
return homebridge.request('/reset');
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Download compressed log files
|
|
71
|
+
* @returns {Promise<Buffer>}
|
|
72
|
+
*/
|
|
73
|
+
async downloadLogs() {
|
|
74
|
+
return homebridge.request('/downloadLogs');
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Register a listener for the 'addAccessory' push event.
|
|
79
|
+
* Fired by server after batch processing completes (~45s after login).
|
|
80
|
+
* Replaces any previously registered listener.
|
|
81
|
+
* @param {function} callback - receives array of L_Station objects
|
|
82
|
+
*/
|
|
83
|
+
onAccessoriesReady(callback) {
|
|
84
|
+
this._on('addAccessory', (event) => {
|
|
85
|
+
callback(event.data);
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Register a listener for admin account error.
|
|
91
|
+
* Replaces any previously registered listener.
|
|
92
|
+
* @param {function} callback
|
|
93
|
+
*/
|
|
94
|
+
onAdminAccountUsed(callback) {
|
|
95
|
+
this._on('AdminAccountUsed', () => {
|
|
96
|
+
callback();
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Register a listener for cache warnings (stale, version mismatch).
|
|
102
|
+
* Replaces any previously registered listener.
|
|
103
|
+
* @param {function} callback - receives { reason, ageDays?, currentVersion?, storedVersion? }
|
|
104
|
+
*/
|
|
105
|
+
onCacheWarning(callback) {
|
|
106
|
+
this._on('cacheWarning', (event) => {
|
|
107
|
+
callback(event.data);
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Register a listener for log download progress.
|
|
113
|
+
* Replaces any previously registered listener.
|
|
114
|
+
* @param {function} callback - receives { progress, status }
|
|
115
|
+
*/
|
|
116
|
+
onDownloadLogsProgress(callback) {
|
|
117
|
+
this._on('downloadLogsProgress', (event) => {
|
|
118
|
+
callback(event.data);
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get system and environment information for issue reporting
|
|
124
|
+
* @returns {Promise<{pluginVersion: string, eufyClientVersion: string, homebridgeVersion: string, nodeVersion: string, os: string, devices: Array}>}
|
|
125
|
+
*/
|
|
126
|
+
async getSystemInfo() {
|
|
127
|
+
return homebridge.request('/systemInfo');
|
|
128
|
+
},
|
|
129
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config service — wraps homebridge plugin config CRUD operations.
|
|
3
|
+
* Manages reading/writing plugin configuration via the Homebridge API.
|
|
4
|
+
*/
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
const Config = {
|
|
7
|
+
_cache: null,
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get the current plugin config (first block).
|
|
11
|
+
* Uses cache if available; call load() to force a fresh read.
|
|
12
|
+
* @returns {Promise<object>}
|
|
13
|
+
*/
|
|
14
|
+
async get() {
|
|
15
|
+
if (this._cache) return this._cache;
|
|
16
|
+
return this.load();
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Load config from Homebridge (always fetches fresh, no side-effects).
|
|
21
|
+
* @returns {Promise<object>}
|
|
22
|
+
*/
|
|
23
|
+
async load() {
|
|
24
|
+
const configs = await homebridge.getPluginConfig();
|
|
25
|
+
this._cache = configs.length > 0 ? configs[0] : {};
|
|
26
|
+
return this._cache;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Update config in memory (does NOT save to disk).
|
|
31
|
+
* @param {object} config - full config object
|
|
32
|
+
*/
|
|
33
|
+
async update(config) {
|
|
34
|
+
this._cache = config;
|
|
35
|
+
await homebridge.updatePluginConfig([config]);
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Save current config to disk (config.json).
|
|
40
|
+
* Call sparingly — only after login or explicit user save.
|
|
41
|
+
*/
|
|
42
|
+
async save() {
|
|
43
|
+
await homebridge.savePluginConfig();
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Update config and immediately save to disk.
|
|
48
|
+
* @param {object} config
|
|
49
|
+
*/
|
|
50
|
+
async updateAndSave(config) {
|
|
51
|
+
await this.update(config);
|
|
52
|
+
await this.save();
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get device config for a specific device by serial number.
|
|
57
|
+
* @param {string} serialNumber
|
|
58
|
+
* @returns {object|undefined}
|
|
59
|
+
*/
|
|
60
|
+
getDeviceConfig(serialNumber) {
|
|
61
|
+
if (!this._cache) return undefined;
|
|
62
|
+
const cameras = this._cache.cameras || [];
|
|
63
|
+
return cameras.find((c) => c.serialNumber === serialNumber);
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get station config for a specific station by serial number.
|
|
68
|
+
* @param {string} serialNumber
|
|
69
|
+
* @returns {object|undefined}
|
|
70
|
+
*/
|
|
71
|
+
getStationConfig(serialNumber) {
|
|
72
|
+
if (!this._cache) return undefined;
|
|
73
|
+
const stations = this._cache.stations || [];
|
|
74
|
+
return stations.find((s) => s.serialNumber === serialNumber);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Update or create camera config for a device.
|
|
79
|
+
* @param {string} serialNumber
|
|
80
|
+
* @param {object} options - config properties to merge
|
|
81
|
+
*/
|
|
82
|
+
async updateDeviceConfig(serialNumber, options) {
|
|
83
|
+
const config = this._cache || await this.get();
|
|
84
|
+
if (!config.cameras) config.cameras = [];
|
|
85
|
+
|
|
86
|
+
const idx = config.cameras.findIndex((c) => c.serialNumber === serialNumber);
|
|
87
|
+
if (idx !== -1) {
|
|
88
|
+
Object.assign(config.cameras[idx], options);
|
|
89
|
+
} else {
|
|
90
|
+
config.cameras.push({ serialNumber, ...options });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
await this.update(config);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Update or create station config.
|
|
98
|
+
* @param {string} serialNumber
|
|
99
|
+
* @param {object} options - config properties to merge
|
|
100
|
+
*/
|
|
101
|
+
async updateStationConfig(serialNumber, options) {
|
|
102
|
+
const config = this._cache || await this.get();
|
|
103
|
+
if (!config.stations) config.stations = [];
|
|
104
|
+
|
|
105
|
+
const idx = config.stations.findIndex((s) => s.serialNumber === serialNumber);
|
|
106
|
+
if (idx !== -1) {
|
|
107
|
+
Object.assign(config.stations[idx], options);
|
|
108
|
+
} else {
|
|
109
|
+
config.stations.push({ serialNumber, ...options });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await this.update(config);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Update global config options (top-level properties).
|
|
117
|
+
* @param {object} options - properties to merge into top-level config
|
|
118
|
+
*/
|
|
119
|
+
async updateGlobal(options) {
|
|
120
|
+
const config = this._cache || await this.get();
|
|
121
|
+
Object.assign(config, options);
|
|
122
|
+
await this.update(config);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Toggle a device in the ignore list.
|
|
127
|
+
* @param {string} serialNumber
|
|
128
|
+
* @param {boolean} ignored - true to ignore, false to un-ignore
|
|
129
|
+
* @param {'device'|'station'} type
|
|
130
|
+
*/
|
|
131
|
+
async toggleIgnore(serialNumber, ignored, type) {
|
|
132
|
+
const config = this._cache || await this.get();
|
|
133
|
+
const key = type === 'device' ? 'ignoreDevices' : 'ignoreStations';
|
|
134
|
+
if (!config[key]) config[key] = [];
|
|
135
|
+
|
|
136
|
+
if (ignored && !config[key].includes(serialNumber)) {
|
|
137
|
+
config[key].push(serialNumber);
|
|
138
|
+
} else if (!ignored) {
|
|
139
|
+
config[key] = config[key].filter((id) => id !== serialNumber);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await this.update(config);
|
|
143
|
+
},
|
|
144
|
+
};
|