@homebridge-plugins/homebridge-eufy-security 0.0.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/CHANGELOG.md +5 -0
- package/FUNDING.yml +1 -0
- package/LICENSE +176 -0
- package/README.md +67 -0
- package/config.schema.json +6 -0
- package/dist/accessories/AutoSyncStationAccessory.js +156 -0
- package/dist/accessories/AutoSyncStationAccessory.js.map +1 -0
- package/dist/accessories/BaseAccessory.js +247 -0
- package/dist/accessories/BaseAccessory.js.map +1 -0
- package/dist/accessories/CameraAccessory.js +431 -0
- package/dist/accessories/CameraAccessory.js.map +1 -0
- package/dist/accessories/Device.js +67 -0
- package/dist/accessories/Device.js.map +1 -0
- package/dist/accessories/EntrySensorAccessory.js +48 -0
- package/dist/accessories/EntrySensorAccessory.js.map +1 -0
- package/dist/accessories/LockAccessory.js +142 -0
- package/dist/accessories/LockAccessory.js.map +1 -0
- package/dist/accessories/MotionSensorAccessory.js +48 -0
- package/dist/accessories/MotionSensorAccessory.js.map +1 -0
- package/dist/accessories/SmartDropAccessory.js +145 -0
- package/dist/accessories/SmartDropAccessory.js.map +1 -0
- package/dist/accessories/StationAccessory.js +371 -0
- package/dist/accessories/StationAccessory.js.map +1 -0
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -0
- package/dist/controller/LocalLivestreamManager.js +116 -0
- package/dist/controller/LocalLivestreamManager.js.map +1 -0
- package/dist/controller/recordingDelegate.js +208 -0
- package/dist/controller/recordingDelegate.js.map +1 -0
- package/dist/controller/snapshotDelegate.js +345 -0
- package/dist/controller/snapshotDelegate.js.map +1 -0
- package/dist/controller/streamingDelegate.js +345 -0
- package/dist/controller/streamingDelegate.js.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.js +2 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/Snapshot-black.png +0 -0
- package/dist/media/camera-disabled.png +0 -0
- package/dist/media/camera-offline.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/media/Snapshot-black.png +0 -0
- package/dist/media/media/camera-disabled.png +0 -0
- package/dist/media/media/camera-offline.png +0 -0
- package/dist/platform.js +716 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.js +38 -0
- package/dist/settings.js.map +1 -0
- package/dist/utils/Talkback.js +92 -0
- package/dist/utils/Talkback.js.map +1 -0
- package/dist/utils/accessoriesStore.js +206 -0
- package/dist/utils/accessoriesStore.js.map +1 -0
- package/dist/utils/configTypes.js +35 -0
- package/dist/utils/configTypes.js.map +1 -0
- package/dist/utils/ffmpeg.js +843 -0
- package/dist/utils/ffmpeg.js.map +1 -0
- package/dist/utils/interfaces.js +8 -0
- package/dist/utils/interfaces.js.map +1 -0
- package/dist/utils/utils.js +44 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/eslint.config.mjs +18 -0
- package/homebridge-eufy-security.png +0 -0
- package/homebridge-ui/public/app.js +225 -0
- package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C30.png +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C31.png +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell2kdual_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell_e340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufy-security-client.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2cpro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycame330_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlightcame340_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/homebase2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase_large.jpg +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/indoorcamc120_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcammini_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamp24_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcams350_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/keypad_large.png +0 -0
- package/homebridge-ui/public/assets/devices/minibase_chime_T8023_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/motionsensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/sensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8503_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8504_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8510P_t8520P_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8502_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8506_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8520_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_video_t8530_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlockwifibridge_t8021_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_card_t87B2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_link_t87B0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocamc210_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocaml20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams220_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocams40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/soloindoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc22_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/unknown.png +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s100_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s120_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell2k_large.png +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbelldual_large.jpg +0 -0
- package/homebridge-ui/public/assets/icons/attach.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_0.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_1.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_2.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_3.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_4.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_5.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_6.svg +1 -0
- package/homebridge-ui/public/assets/icons/bolt.svg +1 -0
- package/homebridge-ui/public/assets/icons/bug-report.svg +1 -0
- package/homebridge-ui/public/assets/icons/copy.svg +1 -0
- package/homebridge-ui/public/assets/icons/delete.svg +1 -0
- package/homebridge-ui/public/assets/icons/download.svg +1 -0
- package/homebridge-ui/public/assets/icons/info.svg +1 -0
- package/homebridge-ui/public/assets/icons/inventory.svg +1 -0
- package/homebridge-ui/public/assets/icons/refresh.svg +1 -0
- package/homebridge-ui/public/assets/icons/satellite_alt.svg +1 -0
- package/homebridge-ui/public/assets/icons/settings.svg +1 -0
- package/homebridge-ui/public/assets/icons/settings_backup_restore.svg +1 -0
- package/homebridge-ui/public/assets/icons/solar_power.svg +1 -0
- package/homebridge-ui/public/assets/icons/warning.svg +1 -0
- package/homebridge-ui/public/components/device-card.js +162 -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 +27 -0
- package/homebridge-ui/public/services/api.js +214 -0
- package/homebridge-ui/public/services/config.js +144 -0
- package/homebridge-ui/public/style.css +775 -0
- package/homebridge-ui/public/utils/countries.js +73 -0
- package/homebridge-ui/public/utils/device-images.js +89 -0
- package/homebridge-ui/public/utils/helpers.js +87 -0
- package/homebridge-ui/public/views/dashboard.js +226 -0
- package/homebridge-ui/public/views/device-detail.js +610 -0
- package/homebridge-ui/public/views/diagnostics.js +296 -0
- package/homebridge-ui/public/views/login.js +636 -0
- package/homebridge-ui/public/views/settings.js +192 -0
- package/homebridge-ui/public/views/unsupported-detail.js +296 -0
- package/homebridge-ui/server.js +1327 -0
- package/media/Snapshot-Unavailable.png +0 -0
- package/media/Snapshot-Unavailable.xcf +0 -0
- package/media/Snapshot-black.png +0 -0
- package/media/camera-disabled.png +0 -0
- package/media/camera-offline.png +0 -0
- package/package.json +64 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostics View — troubleshooting tools.
|
|
3
|
+
* Download diagnostics, enable debug logging, report issues, reset plugin.
|
|
4
|
+
*/
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
const DiagnosticsView = {
|
|
7
|
+
|
|
8
|
+
_downloadInProgress: false,
|
|
9
|
+
|
|
10
|
+
async render(container) {
|
|
11
|
+
container.innerHTML = '';
|
|
12
|
+
|
|
13
|
+
const config = await Config.get();
|
|
14
|
+
|
|
15
|
+
// Header
|
|
16
|
+
const header = document.createElement('div');
|
|
17
|
+
header.className = 'eufy-header';
|
|
18
|
+
|
|
19
|
+
const backBtn = document.createElement('button');
|
|
20
|
+
backBtn.className = 'btn btn-link p-0';
|
|
21
|
+
backBtn.innerHTML = '← Back';
|
|
22
|
+
backBtn.style.textDecoration = 'none';
|
|
23
|
+
backBtn.addEventListener('click', () => App.navigate('dashboard'));
|
|
24
|
+
|
|
25
|
+
const titleEl = document.createElement('h4');
|
|
26
|
+
titleEl.textContent = 'Diagnostics';
|
|
27
|
+
|
|
28
|
+
header.appendChild(backBtn);
|
|
29
|
+
header.appendChild(titleEl);
|
|
30
|
+
header.appendChild(document.createElement('div'));
|
|
31
|
+
container.appendChild(header);
|
|
32
|
+
|
|
33
|
+
// ── Troubleshooting Steps ──
|
|
34
|
+
const stepsSection = document.createElement('div');
|
|
35
|
+
stepsSection.className = 'settings-section';
|
|
36
|
+
|
|
37
|
+
const stepsTitle = document.createElement('div');
|
|
38
|
+
stepsTitle.className = 'detail-section__title';
|
|
39
|
+
stepsTitle.textContent = 'Troubleshooting';
|
|
40
|
+
stepsSection.appendChild(stepsTitle);
|
|
41
|
+
|
|
42
|
+
// Step 1 — Enable Debug Logging
|
|
43
|
+
const step1 = this._stepBlock('1', 'Enable Debug Logging', 'Capture verbose logs to help diagnose the issue.');
|
|
44
|
+
Toggle.render(step1, {
|
|
45
|
+
id: 'toggle-detailed-log',
|
|
46
|
+
label: 'Debug Logging',
|
|
47
|
+
help: 'Enable this, then reproduce the problem before downloading diagnostics.',
|
|
48
|
+
checked: !!config.enableDetailedLogging,
|
|
49
|
+
onChange: async (checked) => {
|
|
50
|
+
await Config.updateGlobal({ enableDetailedLogging: checked });
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
const debugHint = document.createElement('div');
|
|
54
|
+
debugHint.className = 'alert alert-warning mt-2 mb-2';
|
|
55
|
+
debugHint.style.fontSize = '0.85rem';
|
|
56
|
+
debugHint.innerHTML = Helpers.iconHtml('warning.svg') + ' Remember to <strong>disable debug logging</strong> once done — it generates a lot of data and may impact performance.';
|
|
57
|
+
step1.appendChild(debugHint);
|
|
58
|
+
stepsSection.appendChild(step1);
|
|
59
|
+
|
|
60
|
+
// Step 2 — Download Diagnostics
|
|
61
|
+
const step2 = this._stepBlock('2', 'Download Diagnostics', 'Download a zip archive containing log files and accessories data.');
|
|
62
|
+
|
|
63
|
+
const warning = document.createElement('div');
|
|
64
|
+
warning.className = 'alert alert-warning mt-2 mb-2';
|
|
65
|
+
warning.style.fontSize = '0.85rem';
|
|
66
|
+
warning.innerHTML = Helpers.iconHtml('warning.svg') + ' <strong>Security notice:</strong> Diagnostics may contain sensitive session data. If you share this archive with anyone, it is strongly recommended to reset your Eufy account password afterwards.';
|
|
67
|
+
step2.appendChild(warning);
|
|
68
|
+
|
|
69
|
+
const btnDownload = document.createElement('button');
|
|
70
|
+
btnDownload.className = 'btn btn-primary btn-sm';
|
|
71
|
+
btnDownload.innerHTML = ''; btnDownload.appendChild(Helpers.icon('download.svg')); btnDownload.append(' Download Diagnostics');
|
|
72
|
+
btnDownload.addEventListener('click', () => this._downloadDiagnostics(container));
|
|
73
|
+
step2.appendChild(btnDownload);
|
|
74
|
+
|
|
75
|
+
const logProgress = document.createElement('div');
|
|
76
|
+
logProgress.id = 'log-download-progress';
|
|
77
|
+
step2.appendChild(logProgress);
|
|
78
|
+
stepsSection.appendChild(step2);
|
|
79
|
+
|
|
80
|
+
// Step 3 — Report Issue
|
|
81
|
+
const step3 = this._stepBlock('3', 'Report Issue', 'Open a pre-filled bug report on GitHub with your system information.');
|
|
82
|
+
|
|
83
|
+
const attachHint = document.createElement('div');
|
|
84
|
+
attachHint.className = 'alert alert-info mb-2';
|
|
85
|
+
attachHint.style.fontSize = '0.85rem';
|
|
86
|
+
attachHint.innerHTML = Helpers.iconHtml('attach.svg') + ' Don\'t forget to <strong>attach the diagnostics zip</strong> downloaded in step 2 to your GitHub issue.';
|
|
87
|
+
step3.appendChild(attachHint);
|
|
88
|
+
|
|
89
|
+
const btnReport = document.createElement('button');
|
|
90
|
+
btnReport.className = 'btn btn-outline-secondary btn-sm';
|
|
91
|
+
btnReport.innerHTML = ''; btnReport.appendChild(Helpers.icon('bug-report.svg')); btnReport.append(' Report Issue');
|
|
92
|
+
btnReport.addEventListener('click', () => this._reportIssue());
|
|
93
|
+
step3.appendChild(btnReport);
|
|
94
|
+
stepsSection.appendChild(step3);
|
|
95
|
+
|
|
96
|
+
container.appendChild(stepsSection);
|
|
97
|
+
|
|
98
|
+
// ── Clean Storage ──
|
|
99
|
+
const cleanSection = document.createElement('div');
|
|
100
|
+
cleanSection.className = 'settings-section';
|
|
101
|
+
|
|
102
|
+
const cleanTitle = document.createElement('div');
|
|
103
|
+
cleanTitle.className = 'detail-section__title';
|
|
104
|
+
cleanTitle.textContent = 'Clean Storage';
|
|
105
|
+
cleanSection.appendChild(cleanTitle);
|
|
106
|
+
|
|
107
|
+
const cleanDesc = document.createElement('p');
|
|
108
|
+
cleanDesc.className = 'text-muted';
|
|
109
|
+
cleanDesc.style.fontSize = '0.85rem';
|
|
110
|
+
cleanDesc.textContent = 'Delete rotated logs, cached snapshots, and diagnostic archives to free disk space. Current log files, persistent data, and accessories are preserved.';
|
|
111
|
+
cleanSection.appendChild(cleanDesc);
|
|
112
|
+
|
|
113
|
+
const btnClean = document.createElement('button');
|
|
114
|
+
btnClean.className = 'btn btn-outline-warning btn-sm';
|
|
115
|
+
btnClean.innerHTML = ''; btnClean.appendChild(Helpers.icon('settings_backup_restore.svg')); btnClean.append(' Clean Storage');
|
|
116
|
+
btnClean.addEventListener('click', async () => {
|
|
117
|
+
try {
|
|
118
|
+
const result = await Api.cleanStorage();
|
|
119
|
+
homebridge.toast.success(`Deleted ${result.deleted} file(s).`);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
homebridge.toast.error('Failed to clean storage: ' + (e.message || e));
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
cleanSection.appendChild(btnClean);
|
|
125
|
+
|
|
126
|
+
container.appendChild(cleanSection);
|
|
127
|
+
|
|
128
|
+
// ── Reset Plugin ──
|
|
129
|
+
const resetSection = document.createElement('div');
|
|
130
|
+
resetSection.className = 'settings-section';
|
|
131
|
+
|
|
132
|
+
const resetTitle = document.createElement('div');
|
|
133
|
+
resetTitle.className = 'detail-section__title';
|
|
134
|
+
resetTitle.textContent = 'Reset Plugin';
|
|
135
|
+
resetSection.appendChild(resetTitle);
|
|
136
|
+
|
|
137
|
+
const resetDesc = document.createElement('p');
|
|
138
|
+
resetDesc.className = 'text-muted';
|
|
139
|
+
resetDesc.style.fontSize = '0.85rem';
|
|
140
|
+
resetDesc.textContent = 'Delete all persistent data, stored accessories, and logs. You will need to log in again.';
|
|
141
|
+
resetSection.appendChild(resetDesc);
|
|
142
|
+
|
|
143
|
+
const btnReset = document.createElement('button');
|
|
144
|
+
btnReset.className = 'btn btn-outline-danger btn-sm';
|
|
145
|
+
btnReset.innerHTML = ''; btnReset.appendChild(Helpers.icon('settings_backup_restore.svg')); btnReset.append(' Reset Plugin');
|
|
146
|
+
btnReset.addEventListener('click', () => this._confirmReset(container));
|
|
147
|
+
resetSection.appendChild(btnReset);
|
|
148
|
+
|
|
149
|
+
container.appendChild(resetSection);
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// ===== Report Issue =====
|
|
153
|
+
async _reportIssue() {
|
|
154
|
+
try {
|
|
155
|
+
homebridge.toast.info('Gathering system info...', 'Report Issue');
|
|
156
|
+
const info = await Api.getSystemInfo();
|
|
157
|
+
|
|
158
|
+
const envSection = [
|
|
159
|
+
`- **Plugin Version**: ${info.pluginVersion}`,
|
|
160
|
+
`- **Homebridge Version**: ${info.homebridgeVersion}`,
|
|
161
|
+
`- **Node.js Version**: ${info.nodeVersion}`,
|
|
162
|
+
`- **OS**: ${info.os}`,
|
|
163
|
+
`- **eufy-security-client**: ${info.eufyClientVersion}`,
|
|
164
|
+
].join('\n');
|
|
165
|
+
|
|
166
|
+
const params = new URLSearchParams();
|
|
167
|
+
params.set('template', 'bug_report.yml');
|
|
168
|
+
params.set('environment', envSection);
|
|
169
|
+
|
|
170
|
+
const url = 'https://github.com/homebridge-plugins/homebridge-eufy-security/issues/new?' + params.toString();
|
|
171
|
+
window.open(url, '_blank');
|
|
172
|
+
} catch (e) {
|
|
173
|
+
homebridge.toast.error('Could not gather system info. Opening blank issue form.');
|
|
174
|
+
window.open('https://github.com/homebridge-plugins/homebridge-eufy-security/issues/new?template=bug_report.yml', '_blank');
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
// ===== Diagnostics Download =====
|
|
179
|
+
async _downloadDiagnostics(container) {
|
|
180
|
+
if (this._downloadInProgress) return;
|
|
181
|
+
this._downloadInProgress = true;
|
|
182
|
+
|
|
183
|
+
const progressArea = container.querySelector('#log-download-progress');
|
|
184
|
+
if (progressArea) {
|
|
185
|
+
progressArea.innerHTML = `
|
|
186
|
+
<div class="log-progress mt-2">
|
|
187
|
+
<div class="progress">
|
|
188
|
+
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 10%" id="log-progress-bar"></div>
|
|
189
|
+
</div>
|
|
190
|
+
<small class="text-muted" id="log-progress-status">Preparing...</small>
|
|
191
|
+
</div>
|
|
192
|
+
`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Api.onDiagnosticsProgress((data) => {
|
|
196
|
+
const bar = document.querySelector('#log-progress-bar');
|
|
197
|
+
const status = document.querySelector('#log-progress-status');
|
|
198
|
+
if (bar) bar.style.width = data.progress + '%';
|
|
199
|
+
if (status) status.textContent = data.status;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const result = await Api.downloadDiagnostics();
|
|
204
|
+
const rawBuffer = result.buffer || result;
|
|
205
|
+
const filename = result.filename || 'eufy-security-diagnostics.zip';
|
|
206
|
+
const bytes = new Uint8Array(rawBuffer.data || rawBuffer);
|
|
207
|
+
let binary = '';
|
|
208
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
209
|
+
binary += String.fromCharCode(bytes[i]);
|
|
210
|
+
}
|
|
211
|
+
const base64 = btoa(binary);
|
|
212
|
+
const a = document.createElement('a');
|
|
213
|
+
a.href = 'data:application/zip;base64,' + base64;
|
|
214
|
+
a.download = filename;
|
|
215
|
+
document.body.appendChild(a);
|
|
216
|
+
a.click();
|
|
217
|
+
document.body.removeChild(a);
|
|
218
|
+
|
|
219
|
+
homebridge.toast.success('Diagnostics downloaded.');
|
|
220
|
+
} catch (e) {
|
|
221
|
+
homebridge.toast.error('Failed to download diagnostics: ' + (e.message || e));
|
|
222
|
+
} finally {
|
|
223
|
+
this._downloadInProgress = false;
|
|
224
|
+
if (progressArea) progressArea.innerHTML = '';
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
// ===== Reset Confirmation =====
|
|
229
|
+
_confirmReset(container) {
|
|
230
|
+
const existing = container.querySelector('#reset-confirm');
|
|
231
|
+
if (existing) { existing.remove(); return; }
|
|
232
|
+
|
|
233
|
+
const confirm = document.createElement('div');
|
|
234
|
+
confirm.id = 'reset-confirm';
|
|
235
|
+
confirm.className = 'alert alert-danger mt-3';
|
|
236
|
+
confirm.innerHTML = `
|
|
237
|
+
<strong>Are you sure?</strong> This will delete all persistent data, stored accessories, and logs.
|
|
238
|
+
You will need to log in again.
|
|
239
|
+
<div class="mt-2">
|
|
240
|
+
<button class="btn btn-danger btn-sm me-2" id="btn-confirm-reset">Yes, Reset Everything</button>
|
|
241
|
+
<button class="btn btn-outline-secondary btn-sm" id="btn-cancel-reset">Cancel</button>
|
|
242
|
+
</div>
|
|
243
|
+
`;
|
|
244
|
+
|
|
245
|
+
confirm.querySelector('#btn-confirm-reset').addEventListener('click', async () => {
|
|
246
|
+
try {
|
|
247
|
+
await Api.resetPlugin();
|
|
248
|
+
await Config.update({ platform: 'EufySecurity' });
|
|
249
|
+
await Config.save();
|
|
250
|
+
homebridge.toast.success('Plugin reset. Please restart Homebridge.');
|
|
251
|
+
App.state.stations = [];
|
|
252
|
+
App.navigate('login');
|
|
253
|
+
} catch (e) {
|
|
254
|
+
homebridge.toast.error('Reset failed: ' + (e.message || e));
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
confirm.querySelector('#btn-cancel-reset').addEventListener('click', () => {
|
|
259
|
+
confirm.remove();
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
container.appendChild(confirm);
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Create a numbered step block with title and description.
|
|
267
|
+
*/
|
|
268
|
+
_stepBlock(number, title, description) {
|
|
269
|
+
const block = document.createElement('div');
|
|
270
|
+
block.className = 'diag-step';
|
|
271
|
+
|
|
272
|
+
const header = document.createElement('div');
|
|
273
|
+
header.className = 'diag-step__header';
|
|
274
|
+
|
|
275
|
+
const badge = document.createElement('span');
|
|
276
|
+
badge.className = 'diag-step__badge';
|
|
277
|
+
badge.textContent = number;
|
|
278
|
+
header.appendChild(badge);
|
|
279
|
+
|
|
280
|
+
const titleEl = document.createElement('strong');
|
|
281
|
+
titleEl.textContent = title;
|
|
282
|
+
header.appendChild(titleEl);
|
|
283
|
+
|
|
284
|
+
block.appendChild(header);
|
|
285
|
+
|
|
286
|
+
if (description) {
|
|
287
|
+
const desc = document.createElement('p');
|
|
288
|
+
desc.className = 'text-muted mb-2';
|
|
289
|
+
desc.style.fontSize = '0.85rem';
|
|
290
|
+
desc.textContent = description;
|
|
291
|
+
block.appendChild(desc);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return block;
|
|
295
|
+
},
|
|
296
|
+
};
|