UNPKG

homebridge-resideo

Version:

The Resideo plugin allows you to access your Resideo device(s) from HomeKit.

423 lines 20.5 kB
<p class="text-center"> <img src="https://raw.githubusercontent.com/homebridge-plugins/homebridge-resideo/latest/branding/Homebridge_x_Resideo.svg" alt="homebridge-resideo logo" style="width: 40%;" /> </p> <div id="pageIntro" style="display: none;"> <p class="lead text-center">Thank you for installing <strong>homebridge-resideo</strong></p> <p class="lead text-center">Before continuing:</p> <ol> <li class="mb-3">Login / create an account at <a href="https://developer.honeywellhome.com/user" target="_blank" rel="noreferrer noopener">https://developer.honeywellhome.com/user</a>.</li> <li class="mb-3">Click <strong>Create New App</strong>.</li> <li class="mb-3"> Give your application a name, and enter the 'Callback URL' exactly as it is displayed below. <br> <div class="input-group mt-3"> <input type="text" class="form-control" disabled id="copyMe"> <div class="input-group-append"> <button class="btn btn-primary m-0 py-0 px-3" onclick="copyMyText()" type="button"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="mb-1 bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z" /> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z" /> </svg> </button> </div> </div> </li> <li>Enter the generated 'Consumer Key' and 'Consumer Secret' on the next page.</li> </ol> <div class="text-center"> <button type="button" class="btn btn-primary" id="introLink">Continue &rarr;</button> </div> </div> <div id="menuWrapper" class="btn-group w-100 mb-0" role="group" aria-label="UI Menu" style="display: none;"> <button type="button" class="btn btn-primary ml-0" id="menuAccount"> Account </button> <button type="button" class="btn btn-primary" id="menuSettings"> Settings </button> <button type="button" class="btn btn-primary" id="menuDevices"> Devices </button> <button type="button" class="btn btn-primary mr-0" id="menuHome"> Support </button> </div> <div id="pageAccount" class="mt-4" style="display: none;"> <div class="alert alert-warning" style="display: none;" id="validateForm"> Please enter both values </div> <div class="alert alert-success" style="display: none;" id="linkSuccess"> Config saved, please close this window and restart Homebridge </div> <div class="form-group"> <label for="inputConsumerKey">Consumer Key <span class="text-danger">*</span></label> <input type="text" class="form-control" id="inputConsumerKey"> </div> <div class="form-group"> <label for="inputConsumerSecret">Consumer Secret <span class="text-danger">*</span></label> <input type="text" class="form-control" id="inputConsumerSecret"> </div> <div class="form-group text-center"> <button type="button" class="btn btn-primary" id="backToIntro">&larr;</button> <button type="button" class="btn btn-primary" id="linkButton">Continue &rarr;</button> <button type="button" class="btn btn-danger" id="unLinkButton">Unlink Account &rarr;</button> </div> </div> <div id="pageDevices" class="mt-4" style="display: none;"> <div id="deviceInfo"> <form> <div class="form-group"> <select class="form-control" id="deviceSelect"></select> </div> </form> <table class="table w-100" id="deviceTable" style="display: none;"> <thead> <tr class="table-active"> <th scope="col" style="width: 40%;">Device Name</th> <th scope="col" style="width: 60%;" id="displayName"></th> </tr> </thead> <tbody> <tr> <th scope="row">Device ID</th> <td id="deviceID"></td> </tr> <tr> <th scope="row">Model</th> <td id="model"></td> </tr> <tr> <th scope="row">Firmware Version</th> <td id="firmwareRevision"></td> </tr> </tbody> </table> </div> </div> <div id="pageSupport" class="mt-4" style="display: none;"> <p class="text-center lead">Thank you for using <strong>homebridge-resideo</strong></p> <p class="text-center">The links below will take you to our GitHub wiki</p> <h5>Setup</h5> <ul> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki" target="_blank">Wiki Home</a> </li> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki/Configuration" target="_blank">Configuration</a> </li> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki/Beta-Version" target="_blank">Beta Version</a> </li> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki/Node-Version" target="_blank">Node Version</a> </li> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki/Uninstallation" target="_blank">Uninstallation</a> </li> </ul> <h5>Features</h5> <ul> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki/Supported-Devices" target="_blank">Supported Devices</a> </li> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/wiki/Fan-Modes" target="_blank">Fan Modes</a> </li> </ul> <h5>Help/About</h5> <ul> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/issues/new/choose" target="_blank">Support Request</a> </li> <li> <a href="https://github.com/homebridge-plugins/homebridge-resideo/blob/latest/CHANGELOG.md" target="_blank">Changelog</a> </li> <li> <a href="https://github.com/sponsors/donavanbecker" target="_blank">About Me</a> </li> </ul> <h5>Disclaimer</h5> <ul> <li> I am in no way affiliated with Resideo and this plugin is a personal project that I maintain in my free time. </li> <li> Use this plugin entirely at your own risk - please see licence for more information. </li> </ul> </div> <script> ; (async () => { try { const currentConfig = await homebridge.getPluginConfig() const hostname = window.location.hostname try { await homebridge.request('Start Resideo Login Server') } catch (err) { const msg = err.message homebridge.toast.error(msg, 'HTTP Server Not Started') } homebridge.addEventListener('creds-received', async event => { try { if (event.data.access && event.data.refresh) { this.popup.close() currentConfig[0].credentials = { consumerKey: event.data.key, consumerSecret: event.data.secret, accessToken: event.data.access, refreshToken: event.data.refresh } await homebridge.updatePluginConfig(currentConfig) await homebridge.savePluginConfig() homebridge.toast.success("Successfully Linked Resideo Account", "homebridge-resideo") document.getElementById('backToIntro').style.display = 'none' document.getElementById('linkButton').style.display = 'none' document.getElementById('unLinkButton').style.display = 'none' document.getElementById('linkSuccess').style.display = 'block' } else { throw new Error('no access/token received from server') } } catch (err) { console.log(err) homebridge.toast.error('Try again, or see the console message for info.', 'Error') } }) copyMyText = () => { var textToCopy = document.getElementById("copyMe"); textToCopy.select(); document.execCommand("copy"); } linkAccount = async () => { document.getElementById('validateForm').style.display = 'none' if ( !document.getElementById('inputConsumerKey').value || !document.getElementById('inputConsumerSecret').value ) { document.getElementById('validateForm').style.display = 'block' return } const w = 450; const h = 700; const y = window.top.outerHeight / 2 + window.top.screenY - (h / 2); const x = window.top.outerWidth / 2 + window.top.screenX - (w / 2); const urlToOpen = 'http://' + hostname + ':8585/start?' + 'key=' + document.getElementById('inputConsumerKey').value + '&secret=' + document.getElementById('inputConsumerSecret').value + '&host=' + encodeURI(hostname); this.popup = window.open( urlToOpen, 'honeywell-auth', 'toolbar=no, location=no, directories=no, status=no, menubar=no scrollbars=no, resizable=no, copyhistory=no, ' + 'width=' + w + ', height=' + h + ', top=' + y + ', left=' + x, ) } unLinkAccount = async () => { try { document.getElementById('validateForm').style.display = 'none' if ( !document.getElementById('inputConsumerKey').value || !document.getElementById('inputConsumerSecret').value ) { document.getElementById('validateForm').style.display = 'block' return } delete currentConfig[0].credentials await homebridge.updatePluginConfig(currentConfig) await homebridge.savePluginConfig() document.getElementById('inputConsumerKey').value = '' document.getElementById('inputConsumerSecret').value = '' document.getElementById('unLinkButton').style.display = 'none' } catch (err) { console.error(err) homebridge.toast.error('Try again, or see the console message for info.', 'Error') } } showIntro = () => { const introLink = document.getElementById('introLink') document.getElementById('copyMe').value = 'http://' + hostname + ':8585/auth' introLink.addEventListener('click', () => { homebridge.showSpinner() document.getElementById('pageIntro').style.display = 'none' document.getElementById('menuWrapper').style.display = 'inline-flex' showAccount() homebridge.hideSpinner() }) document.getElementById('pageAccount').style.display = 'none' document.getElementById('menuWrapper').style.display = 'none' document.getElementById('pageIntro').style.display = 'block' } showDevices = async () => { homebridge.showSpinner() homebridge.hideSchemaForm() document.getElementById('menuHome').classList.remove('btn-elegant') document.getElementById('menuHome').classList.add('btn-primary') document.getElementById('menuDevices').classList.add('btn-elegant') document.getElementById('menuDevices').classList.remove('btn-primary') document.getElementById('menuAccount').classList.remove('btn-elegant') document.getElementById('menuAccount').classList.add('btn-primary') document.getElementById('menuSettings').classList.remove('btn-elegant') document.getElementById('menuSettings').classList.add('btn-primary') document.getElementById('pageSupport').style.display = 'none' document.getElementById('pageAccount').style.display = 'none' document.getElementById('pageDevices').style.display = 'block' const cachedAccessories = typeof homebridge.getCachedAccessories === 'function' ? await homebridge.getCachedAccessories() : await homebridge.request('/getCachedAccessories') if (cachedAccessories.length > 0) { cachedAccessories.sort((a, b) => { return a.displayName.toLowerCase() > b.displayName.toLowerCase() ? 1 : b.displayName.toLowerCase() > a.displayName.toLowerCase() ? -1 : 0 }) } const deviceSelect = document.getElementById('deviceSelect') deviceSelect.innerHTML = '' cachedAccessories.forEach(a => { const option = document.createElement('option') option.text = a.displayName option.value = a.UUID deviceSelect.add(option) }) showDeviceInfo = async UUID => { homebridge.showSpinner() const thisAcc = cachedAccessories.find(x => x.UUID === UUID) const context = thisAcc.context document.getElementById('displayName').innerHTML = thisAcc.displayName document.getElementById('deviceID').innerHTML = context.deviceID document.getElementById('model').innerHTML = context.model document.getElementById('firmwareRevision').innerHTML = context.firmwareRevision || 'N/A' document.getElementById('deviceTable').style.display = 'inline-table' homebridge.hideSpinner() } deviceSelect.addEventListener('change', event => showDeviceInfo(event.target.value)) if (cachedAccessories.length > 0) { showDeviceInfo(cachedAccessories[0].UUID) } else { const option = document.createElement('option') option.text = 'No Devices' deviceSelect.add(option) deviceSelect.disabled = true } homebridge.hideSpinner() } showSupport = () => { homebridge.showSpinner() homebridge.hideSchemaForm() document.getElementById('menuHome').classList.add('btn-elegant') document.getElementById('menuHome').classList.remove('btn-primary') document.getElementById('menuDevices').classList.remove('btn-elegant') document.getElementById('menuDevices').classList.add('btn-primary') document.getElementById('menuSettings').classList.remove('btn-elegant') document.getElementById('menuSettings').classList.add('btn-primary') document.getElementById('menuAccount').classList.remove('btn-elegant') document.getElementById('menuAccount').classList.add('btn-primary') document.getElementById('pageSupport').style.display = 'block' document.getElementById('pageDevices').style.display = 'none' document.getElementById('pageAccount').style.display = 'none' homebridge.hideSpinner() } showSettings = () => { homebridge.showSpinner() document.getElementById('menuHome').classList.remove('btn-elegant') document.getElementById('menuHome').classList.add('btn-primary') document.getElementById('menuDevices').classList.remove('btn-elegant') document.getElementById('menuDevices').classList.add('btn-primary') document.getElementById('menuSettings').classList.add('btn-elegant') document.getElementById('menuSettings').classList.remove('btn-primary') document.getElementById('menuAccount').classList.remove('btn-elegant') document.getElementById('menuAccount').classList.add('btn-primary') document.getElementById('pageSupport').style.display = 'none' document.getElementById('pageDevices').style.display = 'none' document.getElementById('pageAccount').style.display = 'none' homebridge.showSchemaForm() homebridge.hideSpinner() } showAccount = () => { homebridge.showSpinner() const backToIntro = document.getElementById('backToIntro') backToIntro.addEventListener('click', () => { showIntro() }) backToIntro.style.display = 'none' const linkButton = document.getElementById('linkButton') linkButton.addEventListener('click', () => { linkAccount() }) const unLinkButton = document.getElementById('unLinkButton') unLinkButton.style.display = 'none' unLinkButton.addEventListener('click', () => { unLinkAccount() }) document.getElementById('linkSuccess').style.display = 'none' homebridge.hideSchemaForm() document.getElementById('menuHome').classList.remove('btn-elegant') document.getElementById('menuHome').classList.add('btn-primary') document.getElementById('menuDevices').classList.remove('btn-elegant') document.getElementById('menuDevices').classList.add('btn-primary') document.getElementById('menuAccount').classList.add('btn-elegant') document.getElementById('menuAccount').classList.remove('btn-primary') document.getElementById('menuSettings').classList.remove('btn-elegant') document.getElementById('menuSettings').classList.add('btn-primary') document.getElementById('pageSupport').style.display = 'none' document.getElementById('pageDevices').style.display = 'none' document.getElementById('pageAccount').style.display = 'block' document.getElementById('linkButton').style.display = 'inline-block' let isRelink = false if (currentConfig[0] && currentConfig[0].credentials) { const key = currentConfig[0].credentials.consumerKey || '' const secret = currentConfig[0].credentials.consumerSecret || '' document.getElementById('inputConsumerKey').value = key document.getElementById('inputConsumerSecret').value = secret if (key && secret) { isRelink = true document.getElementById('unLinkButton').style.display = 'inline-block' } else { document.getElementById('unLinkButton').style.display = 'none' } } document.getElementById('linkButton').innerHTML = isRelink ? 'Relink Account &rarr;' : 'Link Account &rarr;' if (!isRelink) { document.getElementById('backToIntro').style.display = 'inline-block' } else { document.getElementById('backToIntro').style.display = 'none' } homebridge.hideSpinner() } menuHome.addEventListener('click', () => showSupport()) menuAccount.addEventListener('click', () => showAccount()) menuDevices.addEventListener('click', () => showDevices()) menuSettings.addEventListener('click', () => showSettings()) if (currentConfig.length) { document.getElementById('menuWrapper').style.display = 'inline-flex' showAccount() } else { currentConfig.push({ name: 'Resideo' }) await homebridge.updatePluginConfig(currentConfig) showIntro() } } catch (err) { homebridge.toast.error(err.message, 'Error') } finally { homebridge.hideSpinner() } })() </script>