@homebridge-plugins/homebridge-resideo 3.0.3-beta.6 → 3.0.3-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/dist/homebridge-ui/public/index.html +211 -311
- package/dist/homebridge-ui/public/lib/featureoptions.js +455 -0
- package/dist/homebridge-ui/public/lib/featureoptions.js.map +1 -0
- package/dist/homebridge-ui/public/lib/webUi-featureoptions.mjs +3765 -0
- package/dist/homebridge-ui/public/lib/webUi.mjs +189 -0
- package/dist/homebridge-ui/server.d.ts.map +1 -1
- package/dist/homebridge-ui/server.js +202 -44
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/resideo-options.d.ts +16 -0
- package/dist/resideo-options.d.ts.map +1 -0
- package/dist/resideo-options.js +43 -0
- package/dist/resideo-options.js.map +1 -0
- package/docs/functions/default.html +1 -1
- package/package.json +6 -2
|
@@ -48,6 +48,25 @@
|
|
|
48
48
|
Support
|
|
49
49
|
</button>
|
|
50
50
|
</div>
|
|
51
|
+
<div id="pageFirstRun" class="mt-4" style="display: none;">
|
|
52
|
+
<div class="alert alert-info">
|
|
53
|
+
<h5>Getting Started</h5>
|
|
54
|
+
<p class="mb-2">Welcome to homebridge-resideo! Let's get your account configured.</p>
|
|
55
|
+
<p class="mb-0">Please enter your Resideo API credentials to continue.</p>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="form-group">
|
|
58
|
+
<label for="firstRunKey">Consumer Key <span class="text-danger">*</span></label>
|
|
59
|
+
<input type="text" class="form-control" id="firstRunKey">
|
|
60
|
+
</div>
|
|
61
|
+
<div class="form-group">
|
|
62
|
+
<label for="firstRunSecret">Consumer Secret <span class="text-danger">*</span></label>
|
|
63
|
+
<input type="text" class="form-control" id="firstRunSecret">
|
|
64
|
+
</div>
|
|
65
|
+
<div id="loginError"> </div>
|
|
66
|
+
<div class="form-group text-center">
|
|
67
|
+
<button type="button" class="btn btn-primary" id="firstRun">Setup Account →</button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
51
70
|
<div id="pageAccount" class="mt-4" style="display: none;">
|
|
52
71
|
<div class="alert alert-warning" style="display: none;" id="validateForm">
|
|
53
72
|
Please enter both values
|
|
@@ -69,15 +88,40 @@
|
|
|
69
88
|
<button type="button" class="btn btn-danger" id="unLinkButton">Unlink Account →</button>
|
|
70
89
|
</div>
|
|
71
90
|
</div>
|
|
91
|
+
<!-- Dynamic device configuration UI will be rendered here by webUI -->
|
|
92
|
+
<div id="pageFeatureOptions" class="mt-4" style="display: none;">
|
|
93
|
+
</div>
|
|
72
94
|
<div id="pageDevices" class="mt-4" style="display: none;">
|
|
95
|
+
<div class="alert alert-info" id="deviceConfigInfo">
|
|
96
|
+
<h5>Device Configuration Made Easy</h5>
|
|
97
|
+
<p class="mb-2">This section shows devices available from your Resideo account and provides dynamic configuration options.</p>
|
|
98
|
+
<p class="mb-0">Select a device below to view its details and configure its settings using the feature options system.</p>
|
|
99
|
+
</div>
|
|
73
100
|
<div id="deviceInfo">
|
|
74
101
|
<h5>Cached Devices</h5>
|
|
75
102
|
<p>These are devices already configured in Homebridge:</p>
|
|
76
103
|
<form>
|
|
77
104
|
<div class="form-group">
|
|
105
|
+
<label for="deviceSelect"><strong>Available Devices:</strong></label>
|
|
78
106
|
<select class="form-control" id="deviceSelect"></select>
|
|
79
107
|
</div>
|
|
80
108
|
</form>
|
|
109
|
+
<div id="quickConfigSection" style="display: none;" class="mt-3">
|
|
110
|
+
<div class="alert alert-success">
|
|
111
|
+
<h6>Quick Configuration</h6>
|
|
112
|
+
<p class="mb-2">Copy the device ID below and paste it into the plugin settings:</p>
|
|
113
|
+
<div class="input-group">
|
|
114
|
+
<input type="text" class="form-control" id="quickDeviceID" readonly>
|
|
115
|
+
<div class="input-group-append">
|
|
116
|
+
<button class="btn btn-outline-secondary" type="button" id="copyDeviceID">Copy</button>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<small class="form-text text-muted mt-2">
|
|
120
|
+
Recommended device class: <span id="recommendedClass"></span><br>
|
|
121
|
+
Suggested device model: <span id="suggestedModel"></span>
|
|
122
|
+
</small>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
81
125
|
<table class="table w-100" id="deviceTable" style="display: none;">
|
|
82
126
|
<thead>
|
|
83
127
|
<tr class="table-active">
|
|
@@ -186,332 +230,188 @@
|
|
|
186
230
|
</li>
|
|
187
231
|
</ul>
|
|
188
232
|
</div>
|
|
189
|
-
<script>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
233
|
+
<script type="module">
|
|
234
|
+
import { webUi } from "./lib/webUi.mjs";
|
|
235
|
+
|
|
236
|
+
// Initialize the webUI with homebridge-plugin-utils
|
|
237
|
+
const ui = new webUi({
|
|
238
|
+
featureOptions: {
|
|
239
|
+
getFeatureOptions: () => homebridge.request('/getFeatureOptions'),
|
|
240
|
+
getDevices: () => homebridge.request('/getDevices'),
|
|
241
|
+
infoPanel: (device) => {
|
|
242
|
+
return `
|
|
243
|
+
<div class="mt-3">
|
|
244
|
+
<h6>Device Information</h6>
|
|
245
|
+
<p><strong>Name:</strong> ${device.name}</p>
|
|
246
|
+
<p><strong>Device ID:</strong> ${device.deviceID}</p>
|
|
247
|
+
<p><strong>Type:</strong> ${device.deviceType || 'Unknown'}</p>
|
|
248
|
+
<p><strong>Location:</strong> ${device.locationName || 'Unknown'}</p>
|
|
249
|
+
<p><strong>Model:</strong> ${device.model}</p>
|
|
250
|
+
<p><strong>Firmware:</strong> ${device.firmwareRevision}</p>
|
|
251
|
+
</div>
|
|
252
|
+
`;
|
|
199
253
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
document.getElementById('backToIntro').style.display = 'none'
|
|
214
|
-
document.getElementById('linkButton').style.display = 'none'
|
|
215
|
-
document.getElementById('unLinkButton').style.display = 'none'
|
|
216
|
-
document.getElementById('linkSuccess').style.display = 'block'
|
|
217
|
-
} else {
|
|
218
|
-
throw new Error('no access/token received from server')
|
|
219
|
-
}
|
|
220
|
-
} catch (err) {
|
|
221
|
-
console.log(err)
|
|
222
|
-
homebridge.toast.error('Try again, or see the console message for info.', 'Error')
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
copyMyText = () => {
|
|
226
|
-
var textToCopy = document.getElementById("copyMe");
|
|
227
|
-
textToCopy.select();
|
|
228
|
-
document.execCommand("copy");
|
|
229
|
-
}
|
|
230
|
-
linkAccount = async () => {
|
|
231
|
-
document.getElementById('validateForm').style.display = 'none'
|
|
232
|
-
if (
|
|
233
|
-
!document.getElementById('inputConsumerKey').value ||
|
|
234
|
-
!document.getElementById('inputConsumerSecret').value
|
|
235
|
-
) {
|
|
236
|
-
document.getElementById('validateForm').style.display = 'block'
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
const w = 450;
|
|
240
|
-
const h = 700;
|
|
241
|
-
const y = window.top.outerHeight / 2 + window.top.screenY - (h / 2);
|
|
242
|
-
const x = window.top.outerWidth / 2 + window.top.screenX - (w / 2);
|
|
243
|
-
const urlToOpen = 'http://' + hostname + ':8585/start?' +
|
|
244
|
-
'key=' + document.getElementById('inputConsumerKey').value +
|
|
245
|
-
'&secret=' + document.getElementById('inputConsumerSecret').value +
|
|
246
|
-
'&host=' + encodeURI(hostname);
|
|
247
|
-
this.popup = window.open(
|
|
248
|
-
urlToOpen, 'honeywell-auth',
|
|
249
|
-
'toolbar=no, location=no, directories=no, status=no, menubar=no scrollbars=no, resizable=no, copyhistory=no, ' +
|
|
250
|
-
'width=' + w + ', height=' + h + ', top=' + y + ', left=' + x,
|
|
251
|
-
)
|
|
252
|
-
}
|
|
253
|
-
unLinkAccount = async () => {
|
|
254
|
-
try {
|
|
255
|
-
document.getElementById('validateForm').style.display = 'none'
|
|
256
|
-
if (
|
|
257
|
-
!document.getElementById('inputConsumerKey').value ||
|
|
258
|
-
!document.getElementById('inputConsumerSecret').value
|
|
259
|
-
) {
|
|
260
|
-
document.getElementById('validateForm').style.display = 'block'
|
|
261
|
-
return
|
|
262
|
-
}
|
|
263
|
-
delete currentConfig[0].credentials
|
|
264
|
-
await homebridge.updatePluginConfig(currentConfig)
|
|
265
|
-
await homebridge.savePluginConfig()
|
|
266
|
-
document.getElementById('inputConsumerKey').value = ''
|
|
267
|
-
document.getElementById('inputConsumerSecret').value = ''
|
|
268
|
-
document.getElementById('unLinkButton').style.display = 'none'
|
|
269
|
-
} catch (err) {
|
|
270
|
-
console.error(err)
|
|
271
|
-
homebridge.toast.error('Try again, or see the console message for info.', 'Error')
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
showIntro = () => {
|
|
275
|
-
const introLink = document.getElementById('introLink')
|
|
276
|
-
document.getElementById('copyMe').value = 'http://' + hostname + ':8585/auth'
|
|
277
|
-
introLink.addEventListener('click', () => {
|
|
278
|
-
homebridge.showSpinner()
|
|
279
|
-
document.getElementById('pageIntro').style.display = 'none'
|
|
280
|
-
document.getElementById('menuWrapper').style.display = 'inline-flex'
|
|
281
|
-
showAccount()
|
|
282
|
-
homebridge.hideSpinner()
|
|
283
|
-
})
|
|
284
|
-
document.getElementById('pageAccount').style.display = 'none'
|
|
285
|
-
document.getElementById('menuWrapper').style.display = 'none'
|
|
286
|
-
document.getElementById('pageIntro').style.display = 'block'
|
|
287
|
-
}
|
|
288
|
-
showDevices = async () => {
|
|
289
|
-
homebridge.showSpinner()
|
|
290
|
-
homebridge.hideSchemaForm()
|
|
291
|
-
document.getElementById('menuHome').classList.remove('btn-elegant')
|
|
292
|
-
document.getElementById('menuHome').classList.add('btn-primary')
|
|
293
|
-
document.getElementById('menuDevices').classList.add('btn-elegant')
|
|
294
|
-
document.getElementById('menuDevices').classList.remove('btn-primary')
|
|
295
|
-
document.getElementById('menuAccount').classList.remove('btn-elegant')
|
|
296
|
-
document.getElementById('menuAccount').classList.add('btn-primary')
|
|
297
|
-
document.getElementById('menuSettings').classList.remove('btn-elegant')
|
|
298
|
-
document.getElementById('menuSettings').classList.add('btn-primary')
|
|
299
|
-
document.getElementById('pageSupport').style.display = 'none'
|
|
300
|
-
document.getElementById('pageAccount').style.display = 'none'
|
|
301
|
-
document.getElementById('pageDevices').style.display = 'block'
|
|
302
|
-
const cachedAccessories =
|
|
303
|
-
typeof homebridge.getCachedAccessories === 'function'
|
|
304
|
-
? await homebridge.getCachedAccessories()
|
|
305
|
-
: await homebridge.request('/getCachedAccessories')
|
|
306
|
-
if (cachedAccessories.length > 0) {
|
|
307
|
-
cachedAccessories.sort((a, b) => {
|
|
308
|
-
return a.displayName.toLowerCase() > b.displayName.toLowerCase()
|
|
309
|
-
? 1
|
|
310
|
-
: b.displayName.toLowerCase() > a.displayName.toLowerCase()
|
|
311
|
-
? -1
|
|
312
|
-
: 0
|
|
313
|
-
})
|
|
314
|
-
}
|
|
315
|
-
const deviceSelect = document.getElementById('deviceSelect')
|
|
316
|
-
deviceSelect.innerHTML = ''
|
|
317
|
-
cachedAccessories.forEach(a => {
|
|
318
|
-
const option = document.createElement('option')
|
|
319
|
-
option.text = a.displayName
|
|
320
|
-
option.value = a.UUID
|
|
321
|
-
deviceSelect.add(option)
|
|
322
|
-
})
|
|
323
|
-
showDeviceInfo = async UUID => {
|
|
324
|
-
homebridge.showSpinner()
|
|
325
|
-
const thisAcc = cachedAccessories.find(x => x.UUID === UUID)
|
|
326
|
-
const context = thisAcc.context
|
|
327
|
-
document.getElementById('displayName').innerHTML = thisAcc.displayName
|
|
328
|
-
document.getElementById('deviceID').innerHTML = context.deviceID
|
|
329
|
-
document.getElementById('model').innerHTML = context.model
|
|
330
|
-
document.getElementById('firmwareRevision').innerHTML = context.firmwareRevision || 'N/A'
|
|
331
|
-
document.getElementById('deviceTable').style.display = 'inline-table'
|
|
332
|
-
homebridge.hideSpinner()
|
|
333
|
-
}
|
|
334
|
-
deviceSelect.addEventListener('change', event => showDeviceInfo(event.target.value))
|
|
335
|
-
if (cachedAccessories.length > 0) {
|
|
336
|
-
showDeviceInfo(cachedAccessories[0].UUID)
|
|
254
|
+
},
|
|
255
|
+
firstRun: {
|
|
256
|
+
isRequired: () => {
|
|
257
|
+
// Check if we need to run first-time setup
|
|
258
|
+
const currentConfig = homebridge.getPluginConfig();
|
|
259
|
+
return !currentConfig[0]?.credentials?.consumerKey || !currentConfig[0]?.credentials?.consumerSecret;
|
|
260
|
+
},
|
|
261
|
+
onStart: () => {
|
|
262
|
+
// Initialize first run form
|
|
263
|
+
const currentConfig = homebridge.getPluginConfig();
|
|
264
|
+
if (Array.isArray(currentConfig) && currentConfig.length > 0 && currentConfig[0].credentials) {
|
|
265
|
+
document.getElementById('firstRunKey').value = currentConfig[0].credentials.consumerKey || '';
|
|
266
|
+
document.getElementById('firstRunSecret').value = currentConfig[0].credentials.consumerSecret || '';
|
|
337
267
|
} else {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
deviceSelect.add(option)
|
|
341
|
-
deviceSelect.disabled = true
|
|
268
|
+
document.getElementById('firstRunKey').value = '';
|
|
269
|
+
document.getElementById('firstRunSecret').value = '';
|
|
342
270
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
document.getElementById('
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const tableDiv = document.getElementById('availableDevicesTable')
|
|
357
|
-
const tableBody = document.getElementById('availableDevicesTableBody')
|
|
358
|
-
|
|
271
|
+
return true;
|
|
272
|
+
},
|
|
273
|
+
onSubmit: async () => {
|
|
274
|
+
// Handle first run setup
|
|
275
|
+
const key = document.getElementById('firstRunKey').value;
|
|
276
|
+
const secret = document.getElementById('firstRunSecret').value;
|
|
277
|
+
const errorDiv = document.getElementById('loginError');
|
|
278
|
+
|
|
279
|
+
if (!key || !secret) {
|
|
280
|
+
errorDiv.innerHTML = '<div class="alert alert-danger">Please enter both Consumer Key and Consumer Secret.</div>';
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
|
|
359
284
|
try {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const response = await homebridge.request('/getAvailableDevices')
|
|
365
|
-
|
|
366
|
-
if (response.status === 'error') {
|
|
367
|
-
messageDiv.className = 'alert alert-danger'
|
|
368
|
-
messageDiv.innerHTML = response.message || 'Failed to load devices'
|
|
369
|
-
messageDiv.style.display = 'block'
|
|
370
|
-
return
|
|
285
|
+
// Test the credentials by attempting to link the account
|
|
286
|
+
const currentConfig = homebridge.getPluginConfig();
|
|
287
|
+
if (!currentConfig[0]) {
|
|
288
|
+
currentConfig.push({ name: 'Resideo' });
|
|
371
289
|
}
|
|
372
290
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
291
|
+
currentConfig[0].credentials = {
|
|
292
|
+
consumerKey: key,
|
|
293
|
+
consumerSecret: secret
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
await homebridge.updatePluginConfig(currentConfig);
|
|
379
297
|
|
|
380
|
-
//
|
|
381
|
-
|
|
298
|
+
// Now trigger the OAuth flow
|
|
299
|
+
await homebridge.request('Start Resideo Login Server');
|
|
382
300
|
|
|
383
|
-
//
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
<span class="badge badge-${device.isOnline ? 'success' : 'secondary'}">
|
|
394
|
-
${device.isOnline ? 'Online' : 'Offline'}
|
|
395
|
-
</span>
|
|
396
|
-
</td>
|
|
397
|
-
`
|
|
398
|
-
tableBody.appendChild(row)
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
tableDiv.style.display = 'table'
|
|
402
|
-
messageDiv.className = 'alert alert-success'
|
|
403
|
-
messageDiv.innerHTML = `Found ${response.data.length} device(s) in your Resideo account. Copy the Device ID to add devices to your configuration.`
|
|
404
|
-
messageDiv.style.display = 'block'
|
|
301
|
+
// Open OAuth popup
|
|
302
|
+
const hostname = window.location.hostname;
|
|
303
|
+
const w = 450;
|
|
304
|
+
const h = 700;
|
|
305
|
+
const y = window.top.outerHeight / 2 + window.top.screenY - (h / 2);
|
|
306
|
+
const x = window.top.outerWidth / 2 + window.top.screenX - (w / 2);
|
|
307
|
+
const urlToOpen = 'http://' + hostname + ':8585/start?' +
|
|
308
|
+
'key=' + encodeURIComponent(key) +
|
|
309
|
+
'&secret=' + encodeURIComponent(secret) +
|
|
310
|
+
'&host=' + encodeURIComponent(hostname);
|
|
405
311
|
|
|
312
|
+
const popup = window.open(
|
|
313
|
+
urlToOpen, 'resideo-auth',
|
|
314
|
+
'toolbar=no, location=no, directories=no, status=no, menubar=no scrollbars=no, resizable=no, copyhistory=no, ' +
|
|
315
|
+
'width=' + w + ', height=' + h + ', top=' + y + ', left=' + x,
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
return new Promise((resolve) => {
|
|
319
|
+
const checkClosed = setInterval(() => {
|
|
320
|
+
if (popup.closed) {
|
|
321
|
+
clearInterval(checkClosed);
|
|
322
|
+
// Check if credentials were updated
|
|
323
|
+
const updatedConfig = homebridge.getPluginConfig();
|
|
324
|
+
if (updatedConfig[0]?.credentials?.accessToken) {
|
|
325
|
+
resolve(true);
|
|
326
|
+
} else {
|
|
327
|
+
errorDiv.innerHTML = '<div class="alert alert-danger">Authentication failed. Please try again.</div>';
|
|
328
|
+
resolve(false);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}, 1000);
|
|
332
|
+
});
|
|
406
333
|
} catch (error) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
messageDiv.style.display = 'block'
|
|
410
|
-
} finally {
|
|
411
|
-
homebridge.hideSpinner()
|
|
334
|
+
errorDiv.innerHTML = `<div class="alert alert-danger">Error: ${error.message}</div>`;
|
|
335
|
+
return false;
|
|
412
336
|
}
|
|
413
337
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
document.getElementById('menuDevices').classList.add('btn-primary')
|
|
436
|
-
document.getElementById('menuSettings').classList.add('btn-elegant')
|
|
437
|
-
document.getElementById('menuSettings').classList.remove('btn-primary')
|
|
438
|
-
document.getElementById('menuAccount').classList.remove('btn-elegant')
|
|
439
|
-
document.getElementById('menuAccount').classList.add('btn-primary')
|
|
440
|
-
document.getElementById('pageSupport').style.display = 'none'
|
|
441
|
-
document.getElementById('pageDevices').style.display = 'none'
|
|
442
|
-
document.getElementById('pageAccount').style.display = 'none'
|
|
443
|
-
homebridge.showSchemaForm()
|
|
444
|
-
homebridge.hideSpinner()
|
|
445
|
-
}
|
|
446
|
-
showAccount = () => {
|
|
447
|
-
homebridge.showSpinner()
|
|
448
|
-
const backToIntro = document.getElementById('backToIntro')
|
|
449
|
-
backToIntro.addEventListener('click', () => {
|
|
450
|
-
showIntro()
|
|
451
|
-
})
|
|
452
|
-
backToIntro.style.display = 'none'
|
|
453
|
-
const linkButton = document.getElementById('linkButton')
|
|
454
|
-
linkButton.addEventListener('click', () => {
|
|
455
|
-
linkAccount()
|
|
456
|
-
})
|
|
457
|
-
const unLinkButton = document.getElementById('unLinkButton')
|
|
458
|
-
unLinkButton.style.display = 'none'
|
|
459
|
-
unLinkButton.addEventListener('click', () => {
|
|
460
|
-
unLinkAccount()
|
|
461
|
-
})
|
|
462
|
-
document.getElementById('linkSuccess').style.display = 'none'
|
|
463
|
-
homebridge.hideSchemaForm()
|
|
464
|
-
document.getElementById('menuHome').classList.remove('btn-elegant')
|
|
465
|
-
document.getElementById('menuHome').classList.add('btn-primary')
|
|
466
|
-
document.getElementById('menuDevices').classList.remove('btn-elegant')
|
|
467
|
-
document.getElementById('menuDevices').classList.add('btn-primary')
|
|
468
|
-
document.getElementById('menuAccount').classList.add('btn-elegant')
|
|
469
|
-
document.getElementById('menuAccount').classList.remove('btn-primary')
|
|
470
|
-
document.getElementById('menuSettings').classList.remove('btn-elegant')
|
|
471
|
-
document.getElementById('menuSettings').classList.add('btn-primary')
|
|
472
|
-
document.getElementById('pageSupport').style.display = 'none'
|
|
473
|
-
document.getElementById('pageDevices').style.display = 'none'
|
|
474
|
-
document.getElementById('pageAccount').style.display = 'block'
|
|
475
|
-
document.getElementById('linkButton').style.display = 'inline-block'
|
|
476
|
-
let isRelink = false
|
|
477
|
-
if (currentConfig[0] && currentConfig[0].credentials) {
|
|
478
|
-
const key = currentConfig[0].credentials.consumerKey || ''
|
|
479
|
-
const secret = currentConfig[0].credentials.consumerSecret || ''
|
|
480
|
-
document.getElementById('inputConsumerKey').value = key
|
|
481
|
-
document.getElementById('inputConsumerSecret').value = secret
|
|
482
|
-
if (key && secret) {
|
|
483
|
-
isRelink = true
|
|
484
|
-
document.getElementById('unLinkButton').style.display = 'inline-block'
|
|
485
|
-
} else {
|
|
486
|
-
document.getElementById('unLinkButton').style.display = 'none'
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
document.getElementById('linkButton').innerHTML = isRelink
|
|
490
|
-
? 'Relink Account →'
|
|
491
|
-
: 'Link Account →'
|
|
492
|
-
if (!isRelink) {
|
|
493
|
-
document.getElementById('backToIntro').style.display = 'inline-block'
|
|
494
|
-
} else {
|
|
495
|
-
document.getElementById('backToIntro').style.display = 'none'
|
|
338
|
+
},
|
|
339
|
+
name: 'homebridge-resideo'
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Legacy functionality for existing UI elements
|
|
343
|
+
const setupLegacyHandlers = () => {
|
|
344
|
+
const currentConfig = homebridge.getPluginConfig();
|
|
345
|
+
const hostname = window.location.hostname;
|
|
346
|
+
|
|
347
|
+
homebridge.addEventListener('creds-received', async event => {
|
|
348
|
+
try {
|
|
349
|
+
if (event.data.access && event.data.refresh) {
|
|
350
|
+
currentConfig[0].credentials = {
|
|
351
|
+
consumerKey: event.data.key,
|
|
352
|
+
consumerSecret: event.data.secret,
|
|
353
|
+
accessToken: event.data.access,
|
|
354
|
+
refreshToken: event.data.refresh
|
|
355
|
+
};
|
|
356
|
+
await homebridge.updatePluginConfig(currentConfig);
|
|
357
|
+
await homebridge.savePluginConfig();
|
|
358
|
+
homebridge.toast.success("Successfully Linked Resideo Account", "homebridge-resideo");
|
|
496
359
|
}
|
|
497
|
-
|
|
360
|
+
} catch (err) {
|
|
361
|
+
console.log(err);
|
|
362
|
+
homebridge.toast.error('Try again, or see the console message for info.', 'Error');
|
|
498
363
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
window.copyMyText = () => {
|
|
367
|
+
const textToCopy = document.getElementById("copyMe");
|
|
368
|
+
textToCopy.select();
|
|
369
|
+
document.execCommand("copy");
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
window.linkAccount = async () => {
|
|
373
|
+
document.getElementById('validateForm').style.display = 'none';
|
|
374
|
+
if (!document.getElementById('inputConsumerKey').value || !document.getElementById('inputConsumerSecret').value) {
|
|
375
|
+
document.getElementById('validateForm').style.display = 'block';
|
|
376
|
+
return;
|
|
510
377
|
}
|
|
378
|
+
const w = 450;
|
|
379
|
+
const h = 700;
|
|
380
|
+
const y = window.top.outerHeight / 2 + window.top.screenY - (h / 2);
|
|
381
|
+
const x = window.top.outerWidth / 2 + window.top.screenX - (w / 2);
|
|
382
|
+
const urlToOpen = 'http://' + hostname + ':8585/start?' +
|
|
383
|
+
'key=' + document.getElementById('inputConsumerKey').value +
|
|
384
|
+
'&secret=' + document.getElementById('inputConsumerSecret').value +
|
|
385
|
+
'&host=' + encodeURI(hostname);
|
|
386
|
+
window.popup = window.open(
|
|
387
|
+
urlToOpen, 'honeywell-auth',
|
|
388
|
+
'toolbar=no, location=no, directories=no, status=no, menubar=no scrollbars=no, resizable=no, copyhistory=no, ' +
|
|
389
|
+
'width=' + w + ', height=' + h + ', top=' + y + ', left=' + x,
|
|
390
|
+
);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// Initialize legacy components if needed for backwards compatibility
|
|
394
|
+
if (!ui.featureOptions.isRequired()) {
|
|
395
|
+
setupLegacyMenus();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
const setupLegacyMenus = () => {
|
|
400
|
+
// Legacy menu functionality for account, devices, support
|
|
401
|
+
document.getElementById('menuAccount')?.addEventListener('click', () => showAccount());
|
|
402
|
+
document.getElementById('menuDevices')?.addEventListener('click', () => showDevices());
|
|
403
|
+
document.getElementById('menuHome')?.addEventListener('click', () => showSupport());
|
|
404
|
+
document.getElementById('menuSettings')?.addEventListener('click', () => showSettings());
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// Show the webUI
|
|
408
|
+
(async () => {
|
|
409
|
+
try {
|
|
410
|
+
await homebridge.request('Start Resideo Login Server');
|
|
411
|
+
setupLegacyHandlers();
|
|
412
|
+
ui.show();
|
|
511
413
|
} catch (err) {
|
|
512
|
-
homebridge.toast.error(err.message, 'Error')
|
|
513
|
-
} finally {
|
|
514
|
-
homebridge.hideSpinner()
|
|
414
|
+
homebridge.toast.error(err.message, 'Error');
|
|
515
415
|
}
|
|
516
|
-
})()
|
|
416
|
+
})();
|
|
517
417
|
</script>
|