@o-lukas/homebridge-smartthings-tv
Version:
This is a plugin for Homebridge. It offers some basic functions to control Samsung TVs using the SmartThings API.
307 lines (265 loc) • 14.3 kB
HTML
<div class="container">
<div id="pat-warning" class="alert alert-warning" role="alert" style="display:none">
You're using personal access tokens (PAT) to access the SmartThings API. As Samsung made some
<a href="https://community.smartthings.com/t/changes-to-personal-access-tokens-pat/292019" target="_blank">major
changes</a> to usage of PATs at then end of 2024 the usage of PATs is not recommended anymore. Please
consider switching to OAuth for authentication.
</div>
<div id="oauth-start" class="alert alert-info" role="info" style="display:none">
To simplify setup of OAuth please use the following button to start a wizard that guides you through the
setup. This wizard can also be used if token has unexpectedly expired.<br>
For a detailed guide please check the <a
href="https://github.com/o-lukas/homebridge-smartthings-tv/blob/main/docs/oauth.md" target="_blank">OAuth
setup
guide</a>.<br>
<button class="btn btn-primary" onclick="showWizard()">Open OAuth wizard</button>
</div>
<div id="wizard" style="display:none">
<h2 class="mb-4">OAuth Setup Wizard</h2>
<div class="nav nav-pills mb-3" id="wizardNav">
<a class="nav-link active" data-target="#step1">SmartThings App</a>
<a class="nav-link" data-target="#step2">Redirection</a>
<a class="nav-link" data-target="#step3">Authorization code</a>
<a class="nav-link" data-target="#step4">Authorization token</a>
</div>
<div class="tab-content">
<div class="tab-pane fade show active" id="step1">
<h4>SmartThings App</h4>
<p>To activate OAuth integration you have to create a SmartThings application. To do so use the
<a href="https://github.com/SmartThingsCommunity/smartthings-cli">smartthings-cli</a>.
To install the CLI use the installation steps from the
<a href="https://github.com/SmartThingsCommunity/smartthings-cli">documentation</a>.
</p>
<p>If installation succeeded use the
<a
href="https://github.com/SmartThingsCommunity/smartthings-cli?tab=readme-ov-file#smartthings-appscreate">apps:create
command</a>
to create a new application. While creating the application make sure you use the matching redirect
URL and scopes defined below.
</p>
<form id="step1Form">
<div class="form-group row">
<label for="oauth-redirect-url" class="col-sm-3 col-form-label font-weight-bold">OAuth redirect
URL</label>
<div class="col-sm-9">
<input type="oauth-redirect-url" class="form-control" id="oauth-redirect-url"
value="https://httpbin.org/get" readonly onfocus="this.removeAttribute('readonly');"
required>
<small class="form-text text-warning">
⚠ You can customize the redirect URL if you want but it is recommended to keep the
default so you can stick to instructions in this wizard.
</small>
</div>
</div>
<div class="form-group row">
<label for="oauth-scopes" class="col-sm-3 col-form-label font-weight-bold">OAuth scopes</label>
<div class="col-sm-9">
<input type="oauth-scopes" class="form-control" id="oauth-scopes"
value="x:devices:* w:devices:* r:devices:*" readonly
onfocus="this.removeAttribute('readonly');" required>
<small class="form-text text-warning">
⚠ You can customize the scopes if you want but it is recommended to keep the default
so you can stick to instructions in this wizard.
</small>
</div>
</div>
<div class="form-group row">
<label for="oauth-client-id" class="col-sm-3 col-form-label font-weight-bold">OAuth client
id</label>
<div class="col-sm-9">
<input type="oauth-client-id" class="form-control" id="oauth-client-id"
placeholder="Paste the OAuth client id" required>
</div>
</div>
<div class="form-group row">
<label for="oauth-client-secret" class="col-sm-3 col-form-label font-weight-bold">OAuth client
secret</label>
<div class="col-sm-9">
<input type="oauth-client-secret" class="form-control" id="oauth-client-secret"
placeholder="Paste the OAuth client secret" required>
</div>
</div>
</form>
<button class="btn btn-primary next" onclick="validateStep1()">Next</button>
</div>
<div class="tab-pane fade" id="step2">
<h4>Redirection</h4>
<p>You will now be redirected to login at SmartThings home page where you have to select desired
location and confirm access for selected scopes.</p>
<p>Afterwards you will be redirected to httpbin. This page will show the OAuth response that is needed
for continuing. To do so paste the <b>args.code</b> value in next step of the wizard.</p>
<button class="btn btn-secondary prev" onclick="prevStep()">Back</button>
<button class="btn btn-primary next" onclick="validateStep2()">Next</button>
</div>
<div class="tab-pane fade" id="step3">
<h4>Authorization code</h4>
<p>Do now paste <b>args.code</b> value shown at httpbin below.</p>
<form id="step3Form">
<div class="form-group row">
<label for="oauth-code" class="col-sm-3 col-form-label font-weight-bold">Authorization
code</label>
<div class="col-sm-9">
<input type="oauth-code" class="form-control" id="oauth-code"
placeholder="Paste the Authorization code" required>
</div>
</div>
</form>
<button class="btn btn-secondary prev" onclick="prevStep()">Back</button>
<button class="btn btn-primary next" onclick="validateStep3()">Next</button>
</div>
<div class="tab-pane fade" id="step4">
<h4>Authorization token</h4>
<p>Your access and refresh token will now be requested and set automatically.</p>
<p>When tokens have been filled in OAuth setup has been successful and you will be redirected to main
config page.</p>
<form id="step4Form">
<div class="form-group row">
<label for="oauth-access-token" class="col-sm-3 col-form-label font-weight-bold">OAuth access
token</label>
<div class="col-sm-9">
<input type="oauth-access-token" class="form-control" id="oauth-access-token"
placeholder="OAuth access token" required readonly>
</div>
</div>
<div class="form-group row">
<label for="oauth-refresh-token" class="col-sm-3 col-form-label font-weight-bold">OAuth refresh
token</label>
<div class="col-sm-9">
<input type="oauth-refresh-token" class="form-control" id="oauth-refresh-token"
placeholder="OAuth refresh token" required readonly>
</div>
</div>
</form>
<button class="btn btn-secondary prev" onclick="prevStep()">Back</button>
<button class="btn btn-success" onclick="validateStep4()">Submit</button>
</div>
</div>
</div>
</div>
<script>
function showWizard() {
homebridge.disableSaveButton();
homebridge.hideSchemaForm();
document.getElementById('wizard').style.display = "block";
document.getElementById('oauth-start').style.display = "none";
document.getElementById('pat-warning').style.display = "none";
}
function hideWizard() {
homebridge.enableSaveButton();
homebridge.showSchemaForm();
document.getElementById('wizard').style.display = "none";
document.getElementById('oauth-start').style.display = "block";
document.getElementById('pat-warning').style.display = "none";
}
async function updateUi() {
const pluginConfig = await homebridge.getPluginConfig();
if (pluginConfig.length === 0) {
pluginConfig[0] = {
platform: "smartthings-tv",
tokenType: "oauth"
};
await homebridge.updatePluginConfig(pluginConfig);
}
switch (pluginConfig[0].tokenType) {
case "oauth":
homebridge.showSchemaForm();
document.getElementById('wizard').style.display = "none";
document.getElementById('oauth-start').style.display = "block";
document.getElementById('pat-warning').style.display = "none";
break;
case "pat":
default:
homebridge.showSchemaForm();
document.getElementById('wizard').style.display = "none";
document.getElementById('oauth-start').style.display = "none";
document.getElementById('pat-warning').style.display =
pluginConfig[0].disablePatWarning === true ? "none" : "block";
break;
}
document.getElementById('oauth-client-id').value = pluginConfig[0].oauthClientId ?? '';
document.getElementById('oauth-client-secret').value = pluginConfig[0].oauthClientSecret ?? '';
}
function validateStep(id) {
var form = document.getElementById(id);
if (form.checkValidity() === false) {
form.classList.add('was-validated');
return false;
} else {
nextStep();
return true;
}
}
async function validateStep1() {
if (validateStep('step1Form')) {
const pluginConfig = await homebridge.getPluginConfig();
pluginConfig[0].oauthClientId = document.getElementById('oauth-client-id').value;
pluginConfig[0].oauthClientSecret = document.getElementById('oauth-client-secret').value;
await homebridge.updatePluginConfig(pluginConfig);
}
}
async function validateStep2() {
nextStep();
requestAuthCode();
}
async function validateStep3() {
if (validateStep('step3Form')) {
homebridge.showSpinner();
try {
await requestAuthToken();
} catch {
homebridge.toast.error("Could not request authorization token");
} finally {
homebridge.hideSpinner();
}
}
}
async function validateStep4() {
if (validateStep('step4Form')) {
const pluginConfig = await homebridge.getPluginConfig();
pluginConfig[0].oauthRefreshToken = document.getElementById('oauth-refresh-token').value;
await homebridge.updatePluginConfig(pluginConfig);
await homebridge.savePluginConfig();
homebridge.toast.success("Restart Homebridge to apply the changes.", "OAuth Config Saved");
hideWizard();
updateUi();
}
}
function nextStep() {
let activeTab = document.querySelector('.nav-pills .active');
let nextTab = activeTab.nextElementSibling;
if (nextTab) changeTab(nextTab);
}
function prevStep() {
let activeTab = document.querySelector('.nav-pills .active');
let prevTab = activeTab.previousElementSibling;
if (prevTab) changeTab(prevTab);
}
function changeTab(targetTab) {
document.querySelector('.nav-pills .active').classList.remove('active');
document.querySelector('.tab-pane.show').classList.remove('show', 'active');
targetTab.classList.add('active');
document.querySelector(targetTab.getAttribute('data-target')).classList.add('show', 'active');
}
async function requestAuthCode() {
const authUrl = await homebridge.request('/authCode', {
clientId: document.getElementById('oauth-client-id').value,
clientSecret: document.getElementById('oauth-client-secret').value,
redirectUrl: document.getElementById('oauth-redirect-url').value,
scopes: document.getElementById('oauth-scopes').value
});
window.open(authUrl, "_blank");
}
async function requestAuthToken() {
const authToken = await homebridge.request('/authToken', {
code: document.getElementById('oauth-code').value,
redirectUrl: document.getElementById('oauth-redirect-url').value,
scopes: document.getElementById('oauth-scopes').value
});
document.getElementById('oauth-access-token').value = authToken.access_token;
document.getElementById('oauth-refresh-token').value = authToken.refresh_token;
}
updateUi();
window.homebridge.addEventListener('configChanged', (event) => {
updateUi();
});
</script>