@o-lukas/homebridge-smartthings-tv 3.0.0-alpha.1 → 3.0.0-alpha.3
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/homebridge-ui/public/index.html +267 -99
- package/package.json +1 -1
|
@@ -153,154 +153,322 @@
|
|
|
153
153
|
</div>
|
|
154
154
|
|
|
155
155
|
<script>
|
|
156
|
+
// Simple logger helpers
|
|
157
|
+
function _log(name, ...args) {
|
|
158
|
+
try {
|
|
159
|
+
console.log(`[index.html] ${name}`, ...args);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
// ignore logging errors
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function _logError(name, err) {
|
|
166
|
+
try {
|
|
167
|
+
// prefer structured console.error, but guard against failures
|
|
168
|
+
if (console && console.error) {
|
|
169
|
+
console.error(`[index.html] ${name}`, err);
|
|
170
|
+
} else {
|
|
171
|
+
_log(`${name} - error`, err && (err.stack || err));
|
|
172
|
+
}
|
|
173
|
+
} catch (e) {
|
|
174
|
+
// ensure logging never throws
|
|
175
|
+
try { _log(`${name} - failed to log error`, e); } catch (_) { /* ignore */ }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
156
179
|
function showWizard() {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
180
|
+
_log('showWizard - start');
|
|
181
|
+
try {
|
|
182
|
+
homebridge.disableSaveButton();
|
|
183
|
+
homebridge.hideSchemaForm();
|
|
184
|
+
document.getElementById('wizard').style.display = "block";
|
|
185
|
+
document.getElementById('oauth-start').style.display = "none";
|
|
186
|
+
document.getElementById('pat-warning').style.display = "none";
|
|
187
|
+
_log('showWizard - done');
|
|
188
|
+
} catch (err) {
|
|
189
|
+
_logError('showWizard - error', err);
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
162
192
|
}
|
|
163
193
|
|
|
164
194
|
function hideWizard() {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
195
|
+
_log('hideWizard - start');
|
|
196
|
+
try {
|
|
197
|
+
homebridge.enableSaveButton();
|
|
198
|
+
homebridge.showSchemaForm();
|
|
199
|
+
document.getElementById('wizard').style.display = "none";
|
|
200
|
+
document.getElementById('oauth-start').style.display = "block";
|
|
201
|
+
document.getElementById('pat-warning').style.display = "none";
|
|
202
|
+
_log('hideWizard - done');
|
|
203
|
+
} catch (err) {
|
|
204
|
+
_logError('hideWizard - error', err);
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
170
207
|
}
|
|
171
208
|
|
|
172
209
|
async function updateUi() {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
pluginConfig
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
210
|
+
_log('updateUi - start');
|
|
211
|
+
try {
|
|
212
|
+
const pluginConfig = await homebridge.getPluginConfig();
|
|
213
|
+
_log('updateUi - got pluginConfig', pluginConfig);
|
|
214
|
+
|
|
215
|
+
// determine whether wizard is currently visible so we don't close it on config change
|
|
216
|
+
const wizardEl = document.getElementById('wizard');
|
|
217
|
+
const wizardOpen = !!(wizardEl && window.getComputedStyle(wizardEl).display !== 'none');
|
|
218
|
+
_log('updateUi - wizardOpen', wizardOpen);
|
|
219
|
+
|
|
220
|
+
if (pluginConfig.length === 0) {
|
|
221
|
+
_log('updateUi - pluginConfig empty, initializing default');
|
|
222
|
+
pluginConfig[0] = {
|
|
223
|
+
platform: "smartthings-tv",
|
|
224
|
+
tokenType: "oauth"
|
|
225
|
+
};
|
|
226
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
227
|
+
_log('updateUi - default pluginConfig saved');
|
|
228
|
+
}
|
|
181
229
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
230
|
+
// Update UI elements but avoid closing the wizard if it's already open.
|
|
231
|
+
switch (pluginConfig[0].tokenType) {
|
|
232
|
+
case "oauth":
|
|
233
|
+
_log('updateUi - tokenType oauth');
|
|
234
|
+
homebridge.showSchemaForm();
|
|
235
|
+
// Only toggle wizard visibility when it's not currently open.
|
|
236
|
+
if (!wizardOpen) {
|
|
237
|
+
document.getElementById('wizard').style.display = "none";
|
|
238
|
+
document.getElementById('oauth-start').style.display = "block";
|
|
239
|
+
document.getElementById('pat-warning').style.display = "none";
|
|
240
|
+
_log('updateUi - wizard was closed, showing oauth-start');
|
|
241
|
+
} else {
|
|
242
|
+
_log('updateUi - wizard open, leaving wizard visible');
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
|
|
246
|
+
case "pat":
|
|
247
|
+
default:
|
|
248
|
+
_log('updateUi - tokenType pat or default', pluginConfig[0].tokenType);
|
|
249
|
+
homebridge.showSchemaForm();
|
|
250
|
+
if (!wizardOpen) {
|
|
251
|
+
document.getElementById('wizard').style.display = "none";
|
|
252
|
+
document.getElementById('oauth-start').style.display = "none";
|
|
253
|
+
document.getElementById('pat-warning').style.display =
|
|
254
|
+
pluginConfig[0].disablePatWarning === true ? "none" : "block";
|
|
255
|
+
_log('updateUi - wizard was closed, applied pat/default visibility');
|
|
256
|
+
} else {
|
|
257
|
+
_log('updateUi - wizard open, leaving wizard visible');
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
199
261
|
|
|
200
|
-
|
|
201
|
-
|
|
262
|
+
document.getElementById('oauth-client-id').value = pluginConfig[0].oauthClientId ?? '';
|
|
263
|
+
document.getElementById('oauth-client-secret').value = pluginConfig[0].oauthClientSecret ?? '';
|
|
264
|
+
|
|
265
|
+
_log('updateUi - end');
|
|
266
|
+
} catch (err) {
|
|
267
|
+
_logError('updateUi - error', err);
|
|
268
|
+
throw err;
|
|
269
|
+
}
|
|
202
270
|
}
|
|
203
271
|
|
|
204
272
|
function validateStep(id) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
form.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
273
|
+
_log('validateStep - start', id);
|
|
274
|
+
try {
|
|
275
|
+
var form = document.getElementById(id);
|
|
276
|
+
if (form.checkValidity() === false) {
|
|
277
|
+
_log('validateStep - invalid', id);
|
|
278
|
+
form.classList.add('was-validated');
|
|
279
|
+
return false;
|
|
280
|
+
} else {
|
|
281
|
+
_log('validateStep - valid, advancing');
|
|
282
|
+
nextStep();
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
} catch (err) {
|
|
286
|
+
_logError('validateStep - error', err);
|
|
287
|
+
throw err;
|
|
212
288
|
}
|
|
213
289
|
}
|
|
214
290
|
|
|
215
291
|
async function validateStep1() {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
292
|
+
_log('validateStep1 - start');
|
|
293
|
+
try {
|
|
294
|
+
if (validateStep('step1Form')) {
|
|
295
|
+
const pluginConfig = await homebridge.getPluginConfig();
|
|
296
|
+
_log('validateStep1 - current pluginConfig', pluginConfig);
|
|
297
|
+
pluginConfig[0].oauthClientId = document.getElementById('oauth-client-id').value;
|
|
298
|
+
pluginConfig[0].oauthClientSecret = document.getElementById('oauth-client-secret').value;
|
|
299
|
+
_log('validateStep1 - updating pluginConfig', {
|
|
300
|
+
oauthClientId: pluginConfig[0].oauthClientId ? '***' : '',
|
|
301
|
+
oauthClientSecret: pluginConfig[0].oauthClientSecret ? '***' : ''
|
|
302
|
+
});
|
|
303
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
304
|
+
_log('validateStep1 - update complete');
|
|
305
|
+
} else {
|
|
306
|
+
_log('validateStep1 - form invalid, abort');
|
|
307
|
+
}
|
|
308
|
+
} catch (err) {
|
|
309
|
+
_logError('validateStep1 - error', err);
|
|
310
|
+
throw err;
|
|
222
311
|
}
|
|
223
312
|
}
|
|
224
313
|
|
|
225
314
|
async function validateStep2() {
|
|
226
|
-
|
|
227
|
-
|
|
315
|
+
_log('validateStep2 - start');
|
|
316
|
+
try {
|
|
317
|
+
nextStep();
|
|
318
|
+
_log('validateStep2 - requested nextStep, calling requestAuthCode');
|
|
319
|
+
requestAuthCode();
|
|
320
|
+
_log('validateStep2 - requestAuthCode called (not awaited)');
|
|
321
|
+
} catch (err) {
|
|
322
|
+
_logError('validateStep2 - error', err);
|
|
323
|
+
throw err;
|
|
324
|
+
}
|
|
228
325
|
}
|
|
229
326
|
|
|
230
327
|
async function validateStep3() {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
328
|
+
_log('validateStep3 - start');
|
|
329
|
+
try {
|
|
330
|
+
if (validateStep('step3Form')) {
|
|
331
|
+
homebridge.showSpinner();
|
|
332
|
+
_log('validateStep3 - spinner shown, requesting token');
|
|
333
|
+
try {
|
|
334
|
+
await requestAuthToken();
|
|
335
|
+
_log('validateStep3 - requestAuthToken succeeded');
|
|
336
|
+
} catch (err) {
|
|
337
|
+
_logError('validateStep3 - requestAuthToken error', err);
|
|
338
|
+
homebridge.toast.error("Could not request authorization token");
|
|
339
|
+
} finally {
|
|
340
|
+
homebridge.hideSpinner();
|
|
341
|
+
_log('validateStep3 - spinner hidden');
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
_log('validateStep3 - form invalid, abort');
|
|
240
345
|
}
|
|
346
|
+
} catch (err) {
|
|
347
|
+
_logError('validateStep3 - error', err);
|
|
348
|
+
throw err;
|
|
241
349
|
}
|
|
242
350
|
}
|
|
243
351
|
|
|
244
352
|
async function validateStep4() {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
353
|
+
_log('validateStep4 - start');
|
|
354
|
+
try {
|
|
355
|
+
if (validateStep('step4Form')) {
|
|
356
|
+
const pluginConfig = await homebridge.getPluginConfig();
|
|
357
|
+
_log('validateStep4 - got pluginConfig', pluginConfig);
|
|
358
|
+
pluginConfig[0].oauthRefreshToken = document.getElementById('oauth-refresh-token').value;
|
|
359
|
+
_log('validateStep4 - setting oauthRefreshToken ***');
|
|
360
|
+
|
|
361
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
362
|
+
await homebridge.savePluginConfig();
|
|
363
|
+
|
|
364
|
+
homebridge.toast.success("Restart Homebridge to apply the changes.", "OAuth Config Saved");
|
|
365
|
+
|
|
366
|
+
hideWizard();
|
|
367
|
+
updateUi();
|
|
368
|
+
_log('validateStep4 - complete');
|
|
369
|
+
} else {
|
|
370
|
+
_log('validateStep4 - form invalid, abort');
|
|
371
|
+
}
|
|
372
|
+
} catch (err) {
|
|
373
|
+
_logError('validateStep4 - error', err);
|
|
374
|
+
throw err;
|
|
256
375
|
}
|
|
257
376
|
}
|
|
258
377
|
|
|
259
378
|
function nextStep() {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
379
|
+
_log('nextStep - start');
|
|
380
|
+
try {
|
|
381
|
+
let activeTab = document.querySelector('.nav-pills .active');
|
|
382
|
+
let nextTab = activeTab.nextElementSibling;
|
|
383
|
+
_log('nextStep - activeTab', activeTab ? activeTab.getAttribute('data-target') : null, 'nextTab', nextTab ? nextTab.getAttribute('data-target') : null);
|
|
384
|
+
if (nextTab) changeTab(nextTab);
|
|
385
|
+
_log('nextStep - done');
|
|
386
|
+
} catch (err) {
|
|
387
|
+
_logError('nextStep - error', err);
|
|
388
|
+
throw err;
|
|
389
|
+
}
|
|
263
390
|
}
|
|
264
391
|
|
|
265
392
|
function prevStep() {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
393
|
+
_log('prevStep - start');
|
|
394
|
+
try {
|
|
395
|
+
let activeTab = document.querySelector('.nav-pills .active');
|
|
396
|
+
let prevTab = activeTab.previousElementSibling;
|
|
397
|
+
_log('prevStep - activeTab', activeTab ? activeTab.getAttribute('data-target') : null, 'prevTab', prevTab ? prevTab.getAttribute('data-target') : null);
|
|
398
|
+
if (prevTab) changeTab(prevTab);
|
|
399
|
+
_log('prevStep - done');
|
|
400
|
+
} catch (err) {
|
|
401
|
+
_logError('prevStep - error', err);
|
|
402
|
+
throw err;
|
|
403
|
+
}
|
|
269
404
|
}
|
|
270
405
|
|
|
271
406
|
function changeTab(targetTab) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
407
|
+
_log('changeTab - start', targetTab ? targetTab.getAttribute('data-target') : targetTab);
|
|
408
|
+
try {
|
|
409
|
+
document.querySelector('.nav-pills .active').classList.remove('active');
|
|
410
|
+
document.querySelector('.tab-pane.show').classList.remove('show', 'active');
|
|
411
|
+
|
|
412
|
+
targetTab.classList.add('active');
|
|
413
|
+
document.querySelector(targetTab.getAttribute('data-target')).classList.add('show', 'active');
|
|
414
|
+
_log('changeTab - done', targetTab.getAttribute('data-target'));
|
|
415
|
+
} catch (err) {
|
|
416
|
+
_logError('changeTab - error', err);
|
|
417
|
+
throw err;
|
|
418
|
+
}
|
|
277
419
|
}
|
|
278
420
|
|
|
279
421
|
async function requestAuthCode() {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
422
|
+
_log('requestAuthCode - start');
|
|
423
|
+
try {
|
|
424
|
+
const payload = {
|
|
425
|
+
clientId: document.getElementById('oauth-client-id').value,
|
|
426
|
+
clientSecret: document.getElementById('oauth-client-secret').value,
|
|
427
|
+
redirectUrl: document.getElementById('oauth-redirect-url').value,
|
|
428
|
+
scopes: document.getElementById('oauth-scopes').value
|
|
429
|
+
};
|
|
430
|
+
_log('requestAuthCode - payload', { clientId: payload.clientId ? '***' : '', redirectUrl: payload.redirectUrl, scopes: payload.scopes });
|
|
431
|
+
|
|
432
|
+
const authUrl = await homebridge.request('/authCode', payload);
|
|
433
|
+
_log('requestAuthCode - got authUrl', authUrl);
|
|
434
|
+
|
|
435
|
+
window.open(authUrl, "_blank");
|
|
436
|
+
_log('requestAuthCode - window.open called');
|
|
437
|
+
return authUrl;
|
|
438
|
+
} catch (err) {
|
|
439
|
+
_logError('requestAuthCode - error', err);
|
|
440
|
+
throw err;
|
|
441
|
+
}
|
|
288
442
|
}
|
|
289
443
|
|
|
290
444
|
async function requestAuthToken() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
445
|
+
_log('requestAuthToken - start');
|
|
446
|
+
try {
|
|
447
|
+
const payload = {
|
|
448
|
+
code: document.getElementById('oauth-code').value,
|
|
449
|
+
redirectUrl: document.getElementById('oauth-redirect-url').value,
|
|
450
|
+
scopes: document.getElementById('oauth-scopes').value
|
|
451
|
+
};
|
|
452
|
+
_log('requestAuthToken - payload', { code: payload.code ? '***' : '', redirectUrl: payload.redirectUrl, scopes: payload.scopes });
|
|
453
|
+
|
|
454
|
+
const authToken = await homebridge.request('/authToken', payload);
|
|
455
|
+
_log('requestAuthToken - got authToken', { access: authToken?.access_token ? '***' : null, refresh: authToken?.refresh_token ? '***' : null });
|
|
456
|
+
|
|
457
|
+
document.getElementById('oauth-access-token').value = authToken.access_token;
|
|
458
|
+
document.getElementById('oauth-refresh-token').value = authToken.refresh_token;
|
|
459
|
+
_log('requestAuthToken - tokens set in UI');
|
|
460
|
+
return authToken;
|
|
461
|
+
} catch (err) {
|
|
462
|
+
_logError('requestAuthToken - error', err);
|
|
463
|
+
throw err;
|
|
464
|
+
}
|
|
299
465
|
}
|
|
300
466
|
|
|
467
|
+
_log('initializing - calling updateUi');
|
|
301
468
|
updateUi();
|
|
302
469
|
|
|
303
470
|
window.homebridge.addEventListener('configChanged', (event) => {
|
|
471
|
+
_log('homebridge.configChanged event received', event);
|
|
304
472
|
updateUi();
|
|
305
473
|
});
|
|
306
474
|
</script>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"displayName": "Homebridge SmartThings TV",
|
|
3
3
|
"name": "@o-lukas/homebridge-smartthings-tv",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "3.0.0-alpha.
|
|
5
|
+
"version": "3.0.0-alpha.3",
|
|
6
6
|
"description": "This is a plugin for Homebridge. It offers some basic functions to control Samsung TVs using the SmartThings API.",
|
|
7
7
|
"author": "o-lukas",
|
|
8
8
|
"license": "MIT",
|