I don’t have much experience with the code for custom tiles. I did my best but can’t get it to work. How might one modify the custom HTML tile to combine multiple hubitat devices into a single custom tile? Here’s my attempt…
<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 thing1 = getThing(1)
    let thing2 = getThing(2)
      //try to find the desired parameter
        let attribute1 = thing1.attributes.find(function(attr){ return attr.name === tileSettings.attribute1});
        let attribute2 = thing2.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>

 )
 )