-
-
Save joshualyon/e17ca4b80b3a82c5730d12ee337de12f to your computer and use it in GitHub Desktop.
Double Hubitat Custom Tile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script> | |
<script src="//cdn.sharptools.io/js/custom-tiles.js"></script> | |
<script> | |
//stub a variable to hold the settings at a higher scope | |
// var settings; //apiSample, deviceId, attribute | |
var tileSettings = { | |
apiSample: "XXXXXXXX", | |
deviceId1: "2374", | |
attribute1: "chart", | |
deviceId2: "2146", | |
attribute2: "chart", | |
} | |
var apiSettings = {}; | |
var timerId; | |
// var REFRESH_INTERVAL = 60 * 60 * 1000; //every 60 minutes? | |
var REFRESH_INTERVAL = 3 * 60 * 1000; // every 3 minutes | |
//get the content element so we can update it later | |
var contentEl = document.getElementById("content1"); | |
var contentE2 = document.getElementById("content2"); | |
//when the tile is ready | |
stio.ready(function(data){ | |
//get the settings from the callback | |
// tileSettings = data.settings; //token, deviceId, attribute | |
//and initialize the tile | |
init(); | |
}); | |
var tapState = 0 | |
function init(){ | |
//parse the relevant settings out of the apiSample | |
parseApiSample(); | |
//make a call to the Hubitat API to get some data | |
refresh().then(function(){ | |
//if the first refresh is successful, schedule the periodic refreshes | |
timerId = setInterval(refresh, REFRESH_INTERVAL); | |
}); | |
} | |
//helper method for logging an error to console, showing a toast, and updating the tile to display 'Error' | |
function showError(message){ | |
console.error(message); | |
stio.showToast(message, "red"); | |
contentEl.innerText = "Error"; | |
contentE2.innerText = "Error"; | |
} | |
//parse out the various components from a provided Maker API URL | |
function parseApiSample(sampleUrl){ | |
//if we weren't passed in an explicit URL to parse | |
if(sampleUrl == null){ | |
//then try to use the sample API URL from the tile settings | |
sampleUrl = tileSettings.apiSample; | |
} | |
//if no URL was provided, let the user know | |
if(sampleUrl == null || sampleUrl === "") showError("No API URL was provided. Please configure the tile."); | |
//if the api isn't the cloud API, let the user know | |
if(sampleUrl.indexOf("cloud.hubitat.com") < 0) showError("Please use the Hubitat Maker API CLOUD URI.") | |
//try to parse out the various parts of the URL we need with a regular expression | |
var re = /https:\/\/cloud\.hubitat\.com\/api\/([^\/]+)\/apps\/([\d]+)\/[^\?]+\?access_token\=([^\&]+)/; | |
var match = sampleUrl.match(re); //array of the various regex matches (0: full string, 1: hub id, 2: app id, 3: token) | |
//pass the parsed settings back into the top-level variable | |
apiSettings = { | |
"hubId": match[1], | |
"appId": match[2], | |
"token": match[3] | |
}; | |
} | |
//helper function to format the parsed data back into a base URI | |
function getBaseUrl(){ | |
return `https://cloud.hubitat.com/api/${apiSettings.hubId}/apps/${apiSettings.appId}` | |
} | |
//helper function to format the token into an axios 'data' object to attach the token as a parameter | |
function getAxiosConfig(){ | |
return {params: {access_token: apiSettings.token}}; | |
} | |
function refresh(){ | |
let promise1 = getThing(1) | |
let promise2 = getThing(2) | |
return Promise.all([promise1, promise2]).then(result=> { | |
//try to find the desired parameter | |
let attribute1 = result[0].attributes.find(function(attr){ return attr.name === tileSettings.attribute1}); | |
let attribute2 = result[1].attributes.find(function(attr){ return attr.name === tileSettings.attribute2}); | |
//if we didn't get the attribute, bail out | |
if(attribute1 == null || attribute2 == null) return showError("Could not find desired attribute"); | |
console.log('got attribute1', attribute1); | |
console.log('got attribute2', attribute2); | |
//showError(attribute.currentValue) | |
//otherwise inject the attribute value as HTML | |
var contentEl = document.getElementById("content1"); | |
contentEl.innerHTML = attribute1.currentValue | |
var contentE2 = document.getElementById("content2"); | |
contentE2.innerHTML = attribute2.currentValue | |
event.preventDefault() | |
}) | |
} | |
function getThing(num){ | |
var deviceId = tileSettings.deviceId1 | |
if (num == 2) deviceId = tileSettings.deviceId2 | |
let url = getBaseUrl() + `/devices/${deviceId}` + `?access_token=` + apiSettings.token | |
let config = getAxiosConfig(); | |
//make the API call | |
return axios.get(url).then(function(response){ | |
//if we got a response with the expected base data | |
if(response.data && response.data.attributes){ | |
//return the response | |
return response.data; //TODO: we could parse it into a more helpful "Thing" object format | |
} | |
}).catch(function(error){ | |
showError("Error communicating with Maker API with url of:" + url) | |
}) | |
} | |
</script> | |
<style> | |
html,body {height: 100%;margin:0;} | |
/* | |
.main-content { | |
display: flex; | |
height:100%; | |
align-items: center; | |
justify-content: center; | |
} | |
*/ | |
/* | |
.main-content #content { | |
text-align: center; /* OPTIONAL center align any text that gets injected */ | |
} | |
/* | |
.main-content #content img { | |
max-width: 100%; /* OPTIONAL scale any inner images if they're too big */ | |
} | |
*/ | |
*/ | |
/* OPTIONAL APPROACH FOR KNOWN CONTENT FORMATS | |
(Uncomment below CSS to use) | |
Another vertical auto-scale approach | |
where the expected inner content from | |
the attribute is known. | |
Makes the 'content' holder flex so | |
we can center and forces the content | |
into a column. | |
Then restricts the to a maximum height | |
and hides the br since it shouldn't | |
display in flex layout. | |
*/ | |
/* | |
#content { | |
display: flex; | |
flex-direction: column; | |
height: 100%; | |
width: 100%; | |
align-items: center; | |
justify-content: center; | |
} | |
#content img { | |
max-height: 70%; | |
} | |
#content br { display: none; } | |
*/ | |
</style> | |
<div class="main-content" id="main-content"> | |
<span id="content1"></span> | |
<span id="content2"></span> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment