Help Developing Custom TIle

Custom Tile
With the help of AI, I’ve created a custom tile that integrates with my Hubitat hub through ST. The dashboard shows metrics calculated from movement & door opening patterns but has several rendering issues. Specifically, my tile incorporates Chart.js for visualization & TensorFlow.js for pattern analysis. I continue to see empty containers where charts should appear & I suspect both libraries might be having timeout, loading & initialization problems within ST. The tile is meant to update in response to Hubitat Global Variable event changes from custom Rule Machine rules built to calculate metrics & update those variables based upon trigger events occurring under specific conditions.

Tabbing Function
My tile features a tab-based navigation system to switch between views, but the tab switching functionality fails to work properly. Clicking the tab buttons registers events (confirmed via console logs), but doesn’t successfully toggle the visibility of the corresponding content sections as expected. Each view contains individual cards with graphs/charts & tooltips, but the content areas remain in their initial state regardless of which tab is selected.

Connecting to Hubitat
Hubitat integration seems intermittent. I’m using the Hubitat Maker API app & created additional tile config. settiings with properly configured access token & Maker API base URL for accessing GLOBAL hub variables used in my Hubitat rules. Perhaps there a limit to how many variables can be retrieved in one request?
Maker API Cloud URL used for accessing Hub global variables:
[https://cloud.hubitat.com/api/[Hub](https://cloud.hubitat.com/api/[Hub) ID]/apps/[Maker AI App ID]/globalVariables?access_token=[Maker API Key]

Misc:
The HTML elements exist in the DOM & have the correct IDs (as far as I now), but the charts never appear. Instead, I see “Loading…” Does ST impose restrictions on certain JavaScript libraries for security reasons? Are there specific initialization sequences needed for complex libraries in the ST environment?

I’m seeking guidance on:

  1. How ST manages loading external libraries like Chart.js& TensorFlow.js in custom tiles successfully
  2. Best practices for implementing tab switching within custom dashboards
  3. Recommendations for ensuring smooth integration between ST & Hubitat (via Maker API).
  4. Tips for diagnosing rendering issues in ST custom tiles &/or guidance on how custom UI controls should be implemented within ST to ensure proper event handling.

I can provide HTML wrapper & JS code snippets for further root/cause analysis by those far more skilled at coding than myself. Just tell me what you need

I’d prefer to solve these issues without completely rebuilding my dashboard as its quite large as a standalone monolithic file.

Hard to say without seeing the code or the output from the browser console logs. In theory if you were having library errors, you would see those in the browser console logs too.

Hi Josh - thanks for following up.Note - I’m a complete newbie when it comes to HTML/JS/CSS coding & browser console debugging (using latest Firefox browser) so have mercy on me:.

I exceed the character limit for posting here when trying to paste in the HTML portion of my tile (the JS that follows is large too). Whats the best way to provide those code snippets to you?

METHOD  URL                                                                                   STATUS         TIME
GET     https://sharptools.io/developer/custom-tiles/BZ547joK3yKItaI0dsD2                     [HTTP/3  304]  199ms
GET     https://fonts.googleapis.com/icon?family=Material+Icons                               [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/materialize-d18f3153.css                           [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/stio-common-components-7093d292.css                [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/app-0ec0e3ea.css                                   [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/app-e131e202.js                                     [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/vendor-firebase-6fad035a.js                         [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/stio-helpers-ba14928c.js                            [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/stio-api-68cc0ee6.js                                [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/vendor-vue-e5e13ae4.js                              [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/stio-api-vendored-bdf2e6c9.js                       [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/stio-common-components-8250a72f.js                  [HTTP/2  200]  0ms
GET     https://js.stripe.com/v3/                                                             [HTTP/3  304]  149ms
GET     https://cdn.sharptools.io/css/pack/vextra-cb6cbc25.css                                [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/imports-4f590a70.js                                 [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/vextra-638af111.js                                  [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/icons-7931d091.js                                   [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/vendor-fa-8270b6ee.js                               [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/icons/apple-touch-icon.png                                  [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/icons/favicon-32x32.png                                     [HTTP/2  200]  0ms
GET     https://js.stripe.com/v3/fingerprinted/js/shared-4347bf9e.js                          [HTTP/3  200]  0ms
GET     https://js.stripe.com/v3/fingerprinted/js/controller-with-preconnect-22858b4.js       [HTTP/3  200]  0ms
GET     https://cdn.sharptools.io/css/pack/stio-css-30b150c3.css                              [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/main-app-6f8bc22f.js                                [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/stio-store-e0a45650.js                              [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/stio-router-43c31879.js                             [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/SocketManager-31aef503.js                           [HTTP/2  200]  0ms
INFO    [SocketManager::success] Initialized. (SocketManager-31aef503.js:1:12585)                    

GET     https://cdn.sharptools.io/css/pack/routerHolder-e3b0c442.css                          [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/routerHolder-ca56364b.js                            [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/modalItemPicker-ad762308.css                       [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/customTilesList-403438d4.css                       [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/tilePreview-0f11526b.css                           [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/materializeSwitch-7e219c38.css                     [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/css/pack/developerHome-41b154b8.css                         [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/developerHome-37c2d0b0.js                           [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/customTilesList-962b3628.js                         [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/modalItemPicker-6f7a26c2.js                         [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/materializeRadio-f0f959b4.js                        [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/tilePreview-5ea42ae6.js                             [HTTP/2  200]  0ms
GET     https://cdn.sharptools.io/js/pack/materializeSwitch-8dd070c6.js                       [HTTP/2  200]  0ms
POST    https://r.stripe.com/b                                                                [HTTP/2  200]  104ms
POST    https://r.stripe.com/b                                                                [HTTP/2  200]  99ms
GET     https://js.stripe.com/v3/m-outer-3437aaddcdf6922d623e172c2d6f9278.html                [HTTP/3  200]  0ms
GET     https://js.stripe.com/v3/fingerprinted/js/m-outer-15a2b40a058ddff1cffdb63779fe3de1.js [HTTP/3  200]  0ms
GET     https://m.stripe.network/inner.html                                                   [HTTP/2  200]  191ms
GET     https://m.stripe.network/out-4.5.44.js                                                [HTTP/2  200]  23ms
POST    https://r.stripe.com/b                                                                [HTTP/2  200]  90ms
GET     https://run.sharptools.app/custom-tile/render?v=3                                     [HTTP/2  200]  0ms
GET     https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css             [HTTP/2  200]  0ms
GET     https://cdn.tailwindcss.com/                                                          [HTTP/2  302]  0ms
GET     https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js                    [HTTP/2  200]  0ms
GET     https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.12.0/dist/tf.min.js                   [HTTP/2  200]  0ms
GET     https://cdn.tailwindcss.com/3.4.16                                                    [HTTP/2  200]  0ms

I don’t see anything out of the ordinary of that log. Most of it is just the base loading of the SharpTools web app (HTTP requests), then at the very end it looks like maybe the loading of your custom resources with Chart.js, Tensorflow.js, etc but no errors.

You could post them online somewhere. For example, I often use GitHub Gists for sharing longer snippets of code… or even GitHub itself when I want to keep a copy of my code history.

Otherwise there’s a whole suite of ‘bin’ services that let you share text or code snippets including codefile, Pastebin, and JSFiddle.

Just make sure that if you have any sensitive information embedded directly in the snippets that you share that they are redacted / removed. eg. API Keys, etc.

OK - here’s the HTML

Did the file perhaps get cutoff?

The last thing I see in the file is:

<!-- Footer -->

But there’s not actually anything after that line and I never saw a script block using the various libraries that were imported at the top of the code snippet.

Here’s the Main JS by itself.

Unfortunately, the SharpTools custom tile stuff in that code seems to be made up APIs that don’t actually exist and thus don’t make sense. As a result, some of the approaches for trying to initialize other parts of the code don’t make sense either.

I would encourage starting small and getting the fundamentals in place first.

The documentation for the stio library that enables Custom Tiles to interact with tile settings, Things, and Variables can be found here:

I guess I have my work cut out for me Josh … including tab switching (vs. creating multiple, individual custom tiles) and successfully integrating Hubitat’s Maker API with Custom tiles to obtain real-time updates from sensor events and /or global hub variable updates.

Upon ingesting the stio library doc link & applying it to my dashboard creation scenario - do you concur with the following? Feel free to confirm or deny as I’m hell-bent on learning how to build custom tiles to fit my specific use cases using SharpTools.

SharpTools Custom Tile Environment Limitations

The SharpTools custom tile environment (STIO) has several important limitations that directly impact your Wellness Patterns dashboard implementation:

1. Isolated Execution Environment

  • Sandboxed iframe: Custom tiles run in a sandboxed iframe with limited access to parent context
  • No direct DOM access outside tile: Cannot directly interact with other tiles or the main dashboard
  • Limited cross-frame communication: Communications with the parent SharpTools environment must use the STIO message passing API

2. Asset Loading Restrictions

  • Limited external resources: Only approved CDNs can be used for external scripts and styles
  • No direct file uploads: Cannot upload JavaScript files - all code must be within the custom tile HTML
  • No module bundling: Cannot use module bundlers like Webpack or Rollup

3. Size and Performance Constraints

  • Code size limitations: Large monolithic code can cause performance issues
  • Render timeouts: Excessive execution time can trigger timeouts in the SharpTools environment
  • Limited error reporting: Error details may be limited in the sandboxed environment

4. Library Compatibility Issues

  • Library conflicts: TensorFlow.js and Chart.js can conflict with SharpTools environment
  • Version constraints: Must use library versions that are compatible with SharpTools
  • No server-side processing: All data processing must happen client-side

How These Limitations Impact Your Dashboard

Your Wellness Patterns dashboard appears to be a monolithic application combining several functionalities:

  1. Chart.js visualizations
  2. TensorFlow.js pattern analysis
  3. Complex DOM manipulations
  4. Data fetching and processing

This creates several specific challenges:

Key Issues to Address

  1. Execution Order Problems:
  • STIO has specific lifecycle events that must be respected
  • Your error suggests execution timing issues with the HTML injection
  1. Resource Loading Sequence:
  • External resources like TensorFlow.js must fully load before being used
  • Your console shows multiple resource loads which may be racing
  1. Code Organization:
  • Monolithic code is difficult to debug in this environment
  • Breaking functionality into discrete STIO-aware modules is essential

Recommended Adaptation Approach

To work effectively within these limitations:

  1. Use STIO Lifecycle Hooks Properly:
    // Replace direct DOM manipulation with:
    window.STIO.ready(function() {
    // Initialize your components here after the tile is fully ready
    });
    Sequential Resource Loading:
    // Ensure dependencies load in correct order:
    window.STIO.loadScript(‘https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.12.0/dist/tf.min.js’)
    .then(() => {
    return window.STIO.loadScript(‘https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js’);
    })
    .then(() => {
    initializeApplication();
    })
    .catch(error => {
    console.error(‘Resource loading error:’, error);
    });
    Self-Contained Modules:
  • Each functional component should be wrapped in an IIFE
  • Each module should register for STIO events rather than using direct DOM events
  • Use namespaced global objects to prevent variable collisions

I’m happy to answer questions about the SharpTools environment, but I don’t think that’s the primary concern here. Your app should mostly run as its own standalone thing from what I’ve seen of your code - the only real involvement of SharpTools is a place to display that app and some lightweight hooks for getting the settings.

Again, I want to reiterate how important I believe it is to start small and get the fundamentals right first.

Sandbox
Yes, the Custom Tile runs in an iframe so it’s sandboxed in that an iframe is like being it’s own mini browser. But why would that be an issue?

If you could build it as a standalone web app, then you could build it as a Custom Tile. But as a Custom Tile you get the added benefit that it can access Things, Variables, and the tiles own settings using the stio library.

In your case, it sounds like most of the code should run fully standalone – the only thing the stio library is used for is getting settings and you should be able to easily mock the settings without the stio library at all if you wanted to develop it completely outside of the Custom Tiles developer tools.

Asset Loading
You are NOT restricted on which CDNs or which libraries you load. And you CAN bundle your code and store it or other assets on your own server and reference them if you wanted to.

Size and Performance
These aren’t specific to SharpTools. Sure, if you use complex libraries or write inefficient code, then it’s going to be slow no matter where it runs.

There are no timeouts or execution time limits or logging limits or anything like that. Again, it’s just an iframe. If you could run the code as a normal standalone webpage, you can run it in a Custom Tile.

Library Compatibility
Same as above. This is just an iframe. There aren’t conflicts or version limitations on libraries.

Of course if you need server side processing, then you need to have a server! You can still integrate server side content with a Custom Tile though. If you think about it, a REST API is just a server listening for a request and responding with a specific format… so clearly that’s possible in a Custom Tile.

Limitations Impact
Again, these are general app design issues rather than unique to SharpTools Custom Tiles.

Yes, many libraries require specific loading order or execution order — especially if the library is broken down into multiple pieces or has other dependencies. That’s just web development.

And yes, the same applies to using the stio library. If you need access to features from the stio library then you need to follow the documentation and use the documented flow. eg stio.ready()

Again, no, there’s no special loading of the external libraries you want to use. You just load them as normal script tags not any special stio.loadScript() stuff as that’s made up.

There’s no special stio event hooks that need to be used for other parts of your app. If the other libraries use DOM events, that’s fine — again it’s just an iframe.

I would again recommend starting with a small working part of your overall goal and layer things on as needed. Each piece should be in a working state before layering on the next piece.

And if you aren’t using the stio library for anything other than retrieving per-tile settings, then in theory you should be able to develop and run your client-side web app anywhere – even in a regular HTML page viewed directly from your filesystem in your browser with the “tile settings” stubbed and you wouldn’t even need the stio library-specific stuff included until everything else is working.

Once all your core code is working it would just be a matter of layering in the stio library part for getting the per-tile settings and I’d be happy to help if you run into trouble with that.

The vast majority of what you’re trying to do should run standalone and at that point layering in the stio hooks for settings would be the easy part. The hard part is building your custom app!

1 Like