[BETA] Homey Custom Tiles

Can you share what you’ve tried so far? The documentation for the Configuration Options from the Google Gauge library is linked in the original post.

So an example might look like:

{ "min": 50, "max": 90, "redFrom": 0, "redTo": 60 }

imageimage

I had simply neglected to put the options within situational characters. Now it works perfectly! Thank you for your quick response Josh!

1 Like

One more question that comes to mind. I have seen that it should be possible to add a suffix after the measurement number in a google gauge (72 in your example above). However, I can’t find that alternative among the configuration options. Is it possible to do this?

I don’t believe it’s part of the configuration options.

I believe you can customize the Google Gauge implementation code to add numeric formatting and suffixes as other community members have, but you would need to tweak the Custom Tile code itself. That’s not included in the version released in this thread.

Reading through the tweaks @kampto made in their version of the gauge, it looks like they use a special NumberFormat() to accomplish adding the suffix.

If the snippet above doesn’t help, you might try creating a new thread and tagging @kampto to see if they would be willing to share any insights.

You would likely want to start your modifications from the original Homey Gauge Source as the version linked in the original thread above is a ‘compiled’ version of that same source code intended to support much older browsers.

1 Like

Where can I place this in the script?

It’s a configuration setting on the instance of the tile on your dashboard.

That quote from my post is from the first post in this thread describing each of the tiles and their features. As noted in that quote, it’s a power-user feature, so you’ll need some understanding of formatting JSON and will need to dig into the linked Google Gauge docs for details on the options.

Thanks Josh.
I did the setting on the instance tile. Perfect. I now can see and adjust the red part to be able to see directly if actual data is within the right window. :ok_hand: :ok_hand: :wave: :wave: :+1: :+1:. Love sharptools and verry happy that you started with Homey. It’s a perfect combination.

2 Likes

I’m unsure if I have done something wrong or there is a limitation with the Homey Image Tile? I have tested the API’s using a gauge and they work and am trying to display a Homey Insight chart. I have set up a camera (advanced virtual device) using Device Capabilities app. When I click on the camera (device) it shows the insights image in Homey. I use the device url in Homey Image Tile but no luck - is blank. Can Homey Image Tile display an image from the advanced virtual device?

If you are referring to the Insights Graphs app from the Homey community, I believe displaying the image directly from the Insights Graphs apps would be better in this case. I wrote up some instructions in the original post:

In theory, if the Advanced Virtual Device exposes the Insights Graph image like a camera, you should be able to use it with the Homey Image Viewer custom tile… I would need more information on how you have things configured and how the AVD device is exposing the image though… still, the alternative direct approach linked above is more streamlined

1 Like

Thanks very much Josh. It’s so simple after exploring a variety of methods. Really appreciated.

1 Like

Updated the code for flows to also get advanced flows:

<script type="application/json" id="tile-settings">
    {
      "schema": "0.1.0",
      "settings": [
        {"name": "token", "label": "Token", "type": "STRING"},
        {"name": "homeyCloudId", "label": "Homey Cloud ID", "type": "STRING"},
        {
          "name": "isFavoritesOnly",
          "label": "Only Show Favorites",
          "type": "BOOLEAN",
          "default": false
        }
      ],
      "name": "Homey Flows"
    }
</script>
<!-- Do not edit above -->
<script src="https://cdn.sharptools.io/js/custom-tiles.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js">
</script>
<div class="main-content" id="mainContent">Initializing...</div>

<style>
    html, body { margin: 0; height:100%; }
    .main-content { 
        width: 100%; height: 100%; 
        padding: 0; margin: 0; 
        display: flex; 
        align-items: center; justify-content: center; 
        text-align: center;
        font-size: min(20vh, 20vw); 
    }
</style>
<script>
var getAxiosConfig = function getAxiosConfig() {
    return {
        "headers": {
            "Authorization": "Bearer " + patToken
        }
    };
};
var onClick = function onClick() {
    if (flows.length === 1) {
        //execute the one flow we have
        executeFlow(flows[0].flowId);
    } else {
        var list = {
            title: "Flows",
            items: []
        };
        //build the list from the flows array
        flows.forEach(function(flow) {
            list.items.push({
                label: flow.name,
                value: flow.id
            });
        });
        //show the list
        stio.showList(list).then(function(picked) {
            //if the user picked something, then execute that flow
            if (picked) {
                executeFlow(picked);
            }
        });
    }
};
var getData = function getData() {
    var promises = [
        getFlowsAndAdvancedFlows()
    ];
    if (isFavoritesOnly) {
        promises.push(getUserMe());
    }
    Promise.all(promises).then(function(promiseResults) {
        if (isFavoritesOnly) {
            flows = favoriteFlowIds.map(function(id) {
                return rawFlows[id];
            }).filter(function(f) {
                return f != null;
            });
        } else {
            flows = Object.values(rawFlows).sort(function(a, b) {
                var _b, _a_name, _a;
                return (_a = a) === null || _a === void 0 ? void 0 : (_a_name = _a.name) === null || _a_name === void 0 ? void 0 : _a_name.localeCompare((_b = b) === null || _b === void 0 ? void 0 : _b.name, undefined, {
                    sensitivity: "base"
                });
            });
        }
        //formatting 
        if (flows.length === 1) {
            content.innerText = flows[0].name;
        } else {
            content.innerText = "Flows";
        }
    }).catch(function(error) {
        console.warn("Error in getData. Probably caught earlier", error.message);
    });
};
var getFlowsAndAdvancedFlows = function getFlowsAndAdvancedFlows() {
    var urlFlows = URL_TEMPLATE.replace("{{cloudId}}", cloudId) + "flow/flow";
    var urlAdvancedFlows = URL_TEMPLATE.replace("{{cloudId}}", cloudId) + "flow/advancedflow";
    
    var promiseFlows = axios.get(urlFlows, getAxiosConfig());
    var promiseAdvancedFlows = axios.get(urlAdvancedFlows, getAxiosConfig());

    return Promise.all([promiseFlows, promiseAdvancedFlows]).then(function(responses) {
        var flowsData = responses[0].data || {};
        var advancedFlowsData = responses[1].data || {};

        // Merge flows and advanced flows
        rawFlows = Object.assign({}, flowsData, advancedFlowsData);
    }).catch(function(error) {
        console.error("Error fetching flows and advanced flows", error);
        content.innerText = "Error fetching flows and advanced flows";
        throw error;
    });
};
var getUserMe = function getUserMe() {
    var url = URL_TEMPLATE.replace("{{cloudId}}", cloudId) + "users/user/me";
    return axios.get(url, getAxiosConfig()).then(function(response) {
        if (!response.data) return;
        userProfile = response.data;
        var flowIds = userProfile && userProfile.properties && userProfile.properties.favoriteFlows;
        if (!Array.isArray(flowIds)) return;
        favoriteFlowIds = flowIds;
    }).catch(function(error) {
        console.error("Error fetching favorites", error);
        content.innerText = "Error fetching favorites";
        throw error; //rethrow the error so the caller doesn't continue
    });
};
var executeFlow = function executeFlow(flowId) {
    var url = URL_TEMPLATE.replace("{{cloudId}}", cloudId) + "flow/advancedflow/";
    url = url + flowId + "/trigger"; // Use advancedflow instead of flow
    axios.post(url, null, getAxiosConfig()).then(function(response) {
        console.log("Response Status", response.status);
    });
};
var content = document.getElementById("mainContent");
var patToken = null;
var cloudId = null;
var flows = [];
var rawFlows = {};
var userProfile;
var favoriteFlowIds = [];
var isFavoritesOnly = false;
var URL_TEMPLATE = "https://{{cloudId}}.connect.athom.com/api/manager/";
content.onclick = onClick; //setup the click handler
stio.ready(function(data) {
    console.log("stio library is ready with token", data.settings.token);
    if (data.settings.token == null) {
        content.innerText = "Please configure the tile";
        return;
    } else {
        patToken = data.settings.token;
        cloudId = data.settings.homeyCloudId;
        isFavoritesOnly = !!data.settings.isFavoritesOnly;
    }
    content.innerText = "Loading...";
    getData();
});
</script>

1 Like

Thanks for sharing! I’ll have to give it a try. :star_struck:

From a quick glance, one thing I noticed is that the executeFlow() always calls the /advancedflow path. Does that actually work for the regular flows too? Otherwise it would likely need some logic to determine what type of flow was clicked and which type it needs to execute so executing the regular flows would work too. :slight_smile:

To be honest, I didn´t try to execute any regular flows… I don´t have any at the moment to try directly. I will look in to it though. Also, if you do it before me, feel free to edit the code and update! (I´m very new to this and self learned so it might not be perfect)

1 Like

9 posts were split to a new topic: Homey Beta Custom Tiles: homey_offline

I have now used Homey Image Viewer to display images from my Ring camera in Homey 2023 - and it works!
But I can’t get the tile to update. If I refresh the screen manually (ie switch between two dashboards), I get a new image, but I can’t get it to happen automatically. Is there something I’m overlooking?

That particular tile refreshes the displayed image every 5 minutes. Per the original post. :point_down:t2:

It was originally written more as a proof-of-concept than a fully polished tile. If anyone wants to try updating the tile to be more realtime in nature, I would be happy to incorporate their changes in the version in the original post. :slight_smile:

Hi Josh … It would be great if you could assign each flow to a tile instead of getting a list of all flows. Can you implement that? VG Uwe

Isn’t there a built-in Logic Card for “A webhook is received” that you could add to a Flow if you wanted to trigger it directly? Then you could copy that URL into a Hyperlink tile.

You could even use the special hyperlink syntax to avoid the Hyperlink Tile opening a new window if you wanted to:

Alternatively, the Homey Flows custom tile is open source, so if anyone wants to modify it to support directly controlling a flow, I’m open to that. :slight_smile:

Hi fellow dashboarders. I am looking for a nice integration of Homey Insights graphs for my Sharptools dashboard. I have tried making a mediatile/Hyperlink tile, but that only works when opened in existing window/new window, not in Modal. Anyone with tips to get this to work a bit smoother?

If you are using the “Insights Graphs” app from the Homey Community, check out my reply further above in this thread.

I wrote some instructions in the Insights Graph thread in the Homey Community describing how you can use those graphs within SharpTools.

Otherwise, can you share more details about how are you currently trying to embed things?