@o-lukas/homebridge-smartthings-tv 2.8.0 → 3.0.0-alpha.2
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 +250 -99
- package/package.json +13 -21
|
@@ -153,154 +153,305 @@
|
|
|
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
|
+
if (pluginConfig.length === 0) {
|
|
216
|
+
_log('updateUi - pluginConfig empty, initializing default');
|
|
217
|
+
pluginConfig[0] = {
|
|
218
|
+
platform: "smartthings-tv",
|
|
219
|
+
tokenType: "oauth"
|
|
220
|
+
};
|
|
221
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
222
|
+
_log('updateUi - default pluginConfig saved');
|
|
223
|
+
}
|
|
181
224
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
225
|
+
switch (pluginConfig[0].tokenType) {
|
|
226
|
+
case "oauth":
|
|
227
|
+
_log('updateUi - tokenType oauth');
|
|
228
|
+
homebridge.showSchemaForm();
|
|
229
|
+
document.getElementById('wizard').style.display = "none";
|
|
230
|
+
document.getElementById('oauth-start').style.display = "block";
|
|
231
|
+
document.getElementById('pat-warning').style.display = "none";
|
|
232
|
+
break;
|
|
233
|
+
|
|
234
|
+
case "pat":
|
|
235
|
+
default:
|
|
236
|
+
_log('updateUi - tokenType pat or default', pluginConfig[0].tokenType);
|
|
237
|
+
homebridge.showSchemaForm();
|
|
238
|
+
document.getElementById('wizard').style.display = "none";
|
|
239
|
+
document.getElementById('oauth-start').style.display = "none";
|
|
240
|
+
document.getElementById('pat-warning').style.display =
|
|
241
|
+
pluginConfig[0].disablePatWarning === true ? "none" : "block";
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
199
244
|
|
|
200
|
-
|
|
201
|
-
|
|
245
|
+
document.getElementById('oauth-client-id').value = pluginConfig[0].oauthClientId ?? '';
|
|
246
|
+
document.getElementById('oauth-client-secret').value = pluginConfig[0].oauthClientSecret ?? '';
|
|
247
|
+
|
|
248
|
+
_log('updateUi - end');
|
|
249
|
+
} catch (err) {
|
|
250
|
+
_logError('updateUi - error', err);
|
|
251
|
+
throw err;
|
|
252
|
+
}
|
|
202
253
|
}
|
|
203
254
|
|
|
204
255
|
function validateStep(id) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
form.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
256
|
+
_log('validateStep - start', id);
|
|
257
|
+
try {
|
|
258
|
+
var form = document.getElementById(id);
|
|
259
|
+
if (form.checkValidity() === false) {
|
|
260
|
+
_log('validateStep - invalid', id);
|
|
261
|
+
form.classList.add('was-validated');
|
|
262
|
+
return false;
|
|
263
|
+
} else {
|
|
264
|
+
_log('validateStep - valid, advancing');
|
|
265
|
+
nextStep();
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
} catch (err) {
|
|
269
|
+
_logError('validateStep - error', err);
|
|
270
|
+
throw err;
|
|
212
271
|
}
|
|
213
272
|
}
|
|
214
273
|
|
|
215
274
|
async function validateStep1() {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
275
|
+
_log('validateStep1 - start');
|
|
276
|
+
try {
|
|
277
|
+
if (validateStep('step1Form')) {
|
|
278
|
+
const pluginConfig = await homebridge.getPluginConfig();
|
|
279
|
+
_log('validateStep1 - current pluginConfig', pluginConfig);
|
|
280
|
+
pluginConfig[0].oauthClientId = document.getElementById('oauth-client-id').value;
|
|
281
|
+
pluginConfig[0].oauthClientSecret = document.getElementById('oauth-client-secret').value;
|
|
282
|
+
_log('validateStep1 - updating pluginConfig', {
|
|
283
|
+
oauthClientId: pluginConfig[0].oauthClientId ? '***' : '',
|
|
284
|
+
oauthClientSecret: pluginConfig[0].oauthClientSecret ? '***' : ''
|
|
285
|
+
});
|
|
286
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
287
|
+
_log('validateStep1 - update complete');
|
|
288
|
+
} else {
|
|
289
|
+
_log('validateStep1 - form invalid, abort');
|
|
290
|
+
}
|
|
291
|
+
} catch (err) {
|
|
292
|
+
_logError('validateStep1 - error', err);
|
|
293
|
+
throw err;
|
|
222
294
|
}
|
|
223
295
|
}
|
|
224
296
|
|
|
225
297
|
async function validateStep2() {
|
|
226
|
-
|
|
227
|
-
|
|
298
|
+
_log('validateStep2 - start');
|
|
299
|
+
try {
|
|
300
|
+
nextStep();
|
|
301
|
+
_log('validateStep2 - requested nextStep, calling requestAuthCode');
|
|
302
|
+
requestAuthCode();
|
|
303
|
+
_log('validateStep2 - requestAuthCode called (not awaited)');
|
|
304
|
+
} catch (err) {
|
|
305
|
+
_logError('validateStep2 - error', err);
|
|
306
|
+
throw err;
|
|
307
|
+
}
|
|
228
308
|
}
|
|
229
309
|
|
|
230
310
|
async function validateStep3() {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
311
|
+
_log('validateStep3 - start');
|
|
312
|
+
try {
|
|
313
|
+
if (validateStep('step3Form')) {
|
|
314
|
+
homebridge.showSpinner();
|
|
315
|
+
_log('validateStep3 - spinner shown, requesting token');
|
|
316
|
+
try {
|
|
317
|
+
await requestAuthToken();
|
|
318
|
+
_log('validateStep3 - requestAuthToken succeeded');
|
|
319
|
+
} catch (err) {
|
|
320
|
+
_logError('validateStep3 - requestAuthToken error', err);
|
|
321
|
+
homebridge.toast.error("Could not request authorization token");
|
|
322
|
+
} finally {
|
|
323
|
+
homebridge.hideSpinner();
|
|
324
|
+
_log('validateStep3 - spinner hidden');
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
_log('validateStep3 - form invalid, abort');
|
|
240
328
|
}
|
|
329
|
+
} catch (err) {
|
|
330
|
+
_logError('validateStep3 - error', err);
|
|
331
|
+
throw err;
|
|
241
332
|
}
|
|
242
333
|
}
|
|
243
334
|
|
|
244
335
|
async function validateStep4() {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
336
|
+
_log('validateStep4 - start');
|
|
337
|
+
try {
|
|
338
|
+
if (validateStep('step4Form')) {
|
|
339
|
+
const pluginConfig = await homebridge.getPluginConfig();
|
|
340
|
+
_log('validateStep4 - got pluginConfig', pluginConfig);
|
|
341
|
+
pluginConfig[0].oauthRefreshToken = document.getElementById('oauth-refresh-token').value;
|
|
342
|
+
_log('validateStep4 - setting oauthRefreshToken ***');
|
|
343
|
+
|
|
344
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
345
|
+
await homebridge.savePluginConfig();
|
|
346
|
+
|
|
347
|
+
homebridge.toast.success("Restart Homebridge to apply the changes.", "OAuth Config Saved");
|
|
348
|
+
|
|
349
|
+
hideWizard();
|
|
350
|
+
updateUi();
|
|
351
|
+
_log('validateStep4 - complete');
|
|
352
|
+
} else {
|
|
353
|
+
_log('validateStep4 - form invalid, abort');
|
|
354
|
+
}
|
|
355
|
+
} catch (err) {
|
|
356
|
+
_logError('validateStep4 - error', err);
|
|
357
|
+
throw err;
|
|
256
358
|
}
|
|
257
359
|
}
|
|
258
360
|
|
|
259
361
|
function nextStep() {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
362
|
+
_log('nextStep - start');
|
|
363
|
+
try {
|
|
364
|
+
let activeTab = document.querySelector('.nav-pills .active');
|
|
365
|
+
let nextTab = activeTab.nextElementSibling;
|
|
366
|
+
_log('nextStep - activeTab', activeTab ? activeTab.getAttribute('data-target') : null, 'nextTab', nextTab ? nextTab.getAttribute('data-target') : null);
|
|
367
|
+
if (nextTab) changeTab(nextTab);
|
|
368
|
+
_log('nextStep - done');
|
|
369
|
+
} catch (err) {
|
|
370
|
+
_logError('nextStep - error', err);
|
|
371
|
+
throw err;
|
|
372
|
+
}
|
|
263
373
|
}
|
|
264
374
|
|
|
265
375
|
function prevStep() {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
376
|
+
_log('prevStep - start');
|
|
377
|
+
try {
|
|
378
|
+
let activeTab = document.querySelector('.nav-pills .active');
|
|
379
|
+
let prevTab = activeTab.previousElementSibling;
|
|
380
|
+
_log('prevStep - activeTab', activeTab ? activeTab.getAttribute('data-target') : null, 'prevTab', prevTab ? prevTab.getAttribute('data-target') : null);
|
|
381
|
+
if (prevTab) changeTab(prevTab);
|
|
382
|
+
_log('prevStep - done');
|
|
383
|
+
} catch (err) {
|
|
384
|
+
_logError('prevStep - error', err);
|
|
385
|
+
throw err;
|
|
386
|
+
}
|
|
269
387
|
}
|
|
270
388
|
|
|
271
389
|
function changeTab(targetTab) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
390
|
+
_log('changeTab - start', targetTab ? targetTab.getAttribute('data-target') : targetTab);
|
|
391
|
+
try {
|
|
392
|
+
document.querySelector('.nav-pills .active').classList.remove('active');
|
|
393
|
+
document.querySelector('.tab-pane.show').classList.remove('show', 'active');
|
|
394
|
+
|
|
395
|
+
targetTab.classList.add('active');
|
|
396
|
+
document.querySelector(targetTab.getAttribute('data-target')).classList.add('show', 'active');
|
|
397
|
+
_log('changeTab - done', targetTab.getAttribute('data-target'));
|
|
398
|
+
} catch (err) {
|
|
399
|
+
_logError('changeTab - error', err);
|
|
400
|
+
throw err;
|
|
401
|
+
}
|
|
277
402
|
}
|
|
278
403
|
|
|
279
404
|
async function requestAuthCode() {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
405
|
+
_log('requestAuthCode - start');
|
|
406
|
+
try {
|
|
407
|
+
const payload = {
|
|
408
|
+
clientId: document.getElementById('oauth-client-id').value,
|
|
409
|
+
clientSecret: document.getElementById('oauth-client-secret').value,
|
|
410
|
+
redirectUrl: document.getElementById('oauth-redirect-url').value,
|
|
411
|
+
scopes: document.getElementById('oauth-scopes').value
|
|
412
|
+
};
|
|
413
|
+
_log('requestAuthCode - payload', { clientId: payload.clientId ? '***' : '', redirectUrl: payload.redirectUrl, scopes: payload.scopes });
|
|
414
|
+
|
|
415
|
+
const authUrl = await homebridge.request('/authCode', payload);
|
|
416
|
+
_log('requestAuthCode - got authUrl', authUrl);
|
|
417
|
+
|
|
418
|
+
window.open(authUrl, "_blank");
|
|
419
|
+
_log('requestAuthCode - window.open called');
|
|
420
|
+
return authUrl;
|
|
421
|
+
} catch (err) {
|
|
422
|
+
_logError('requestAuthCode - error', err);
|
|
423
|
+
throw err;
|
|
424
|
+
}
|
|
288
425
|
}
|
|
289
426
|
|
|
290
427
|
async function requestAuthToken() {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
428
|
+
_log('requestAuthToken - start');
|
|
429
|
+
try {
|
|
430
|
+
const payload = {
|
|
431
|
+
code: document.getElementById('oauth-code').value,
|
|
432
|
+
redirectUrl: document.getElementById('oauth-redirect-url').value,
|
|
433
|
+
scopes: document.getElementById('oauth-scopes').value
|
|
434
|
+
};
|
|
435
|
+
_log('requestAuthToken - payload', { code: payload.code ? '***' : '', redirectUrl: payload.redirectUrl, scopes: payload.scopes });
|
|
436
|
+
|
|
437
|
+
const authToken = await homebridge.request('/authToken', payload);
|
|
438
|
+
_log('requestAuthToken - got authToken', { access: authToken?.access_token ? '***' : null, refresh: authToken?.refresh_token ? '***' : null });
|
|
439
|
+
|
|
440
|
+
document.getElementById('oauth-access-token').value = authToken.access_token;
|
|
441
|
+
document.getElementById('oauth-refresh-token').value = authToken.refresh_token;
|
|
442
|
+
_log('requestAuthToken - tokens set in UI');
|
|
443
|
+
return authToken;
|
|
444
|
+
} catch (err) {
|
|
445
|
+
_logError('requestAuthToken - error', err);
|
|
446
|
+
throw err;
|
|
447
|
+
}
|
|
299
448
|
}
|
|
300
449
|
|
|
450
|
+
_log('initializing - calling updateUi');
|
|
301
451
|
updateUi();
|
|
302
452
|
|
|
303
453
|
window.homebridge.addEventListener('configChanged', (event) => {
|
|
454
|
+
_log('homebridge.configChanged event received', event);
|
|
304
455
|
updateUi();
|
|
305
456
|
});
|
|
306
457
|
</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": "
|
|
5
|
+
"version": "3.0.0-alpha.2",
|
|
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",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
],
|
|
28
28
|
"main": "dist/index.js",
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": "^
|
|
31
|
-
"homebridge": "^1.
|
|
30
|
+
"node": "^20 || ^22 || ^24",
|
|
31
|
+
"homebridge": "^1.8.0 || ^2.0.0-beta.0"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "rimraf ./dist && tsc",
|
|
@@ -40,32 +40,24 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@homebridge/plugin-ui-utils": "^2.1.0",
|
|
42
42
|
"@smartthings/core-sdk": "^8.4.1",
|
|
43
|
-
"ping": "^0.
|
|
43
|
+
"ping": "^1.0.0",
|
|
44
44
|
"simple-oauth2": "^5.1.0",
|
|
45
45
|
"wol": "^1.0.7"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@
|
|
48
|
+
"@eslint/js": "^9.36.0",
|
|
49
|
+
"@types/node": "^24.6.2",
|
|
49
50
|
"@types/ping": "^0.4.4",
|
|
50
51
|
"@types/wol": "^1.0.4",
|
|
51
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
52
|
-
"@typescript-eslint/parser": "^8.
|
|
53
|
-
"eslint": "^9.
|
|
54
|
-
"homebridge": "^
|
|
52
|
+
"@typescript-eslint/eslint-plugin": "^8.45.0",
|
|
53
|
+
"@typescript-eslint/parser": "^8.45.0",
|
|
54
|
+
"eslint": "^9.37.0",
|
|
55
|
+
"homebridge": "^2.0.0-beta.30",
|
|
55
56
|
"nodemon": "^3.1.10",
|
|
56
57
|
"rimraf": "^6.0.1",
|
|
57
|
-
"semantic-release": "^24.2.
|
|
58
|
+
"semantic-release": "^24.2.9",
|
|
58
59
|
"ts-node": "^10.9.2",
|
|
59
|
-
"typescript": "^5.
|
|
60
|
-
"typescript-eslint": "^8.
|
|
61
|
-
},
|
|
62
|
-
"release": {
|
|
63
|
-
"branches": [
|
|
64
|
-
"main",
|
|
65
|
-
{
|
|
66
|
-
"name": "next",
|
|
67
|
-
"prerelease": true
|
|
68
|
-
}
|
|
69
|
-
]
|
|
60
|
+
"typescript": "^5.9.3",
|
|
61
|
+
"typescript-eslint": "^8.45.0"
|
|
70
62
|
}
|
|
71
63
|
}
|