[BETA] Homey Custom Tiles

Thanks for the feedback! I’ve pushed an update to the Homey Flow tile which has the following enhancements:

  • With the favorites only option, the sort order of your favorites is used
  • Without the favorites option, alphabetical sorting is used (case and locale insensitive)

I’ve also updated the first post in the thread with details about the scopes needed if you use the Homey API Key approach (per your email question). Please note that I haven’t tested these closely, so if you experience something different, please share what worked for you here!

1 Like

The first post has been updated with information about the Homey Image Display custom tile that a handful of people had been testing.

I’ve also updated the Gauge Tile to better accommodate various Homey Sample URL formats for devices. You can use the steps under :page_facing_up:Update Imported Code to update your existing tiles.

1 Like

Hallo.
I’m new here, learning with Sharptools.
I have Homey Pro 2019 + about 150 Zwave Zigbee and WIFI devices and many flows.
Homey flows Custom Tiles really won’t work in this version of Homey?
Thx for the reply

Alex

I suspect it might be possible to modify the custom tile implementation to use the same trick that the gauge tile uses to support 2019 hubs. There just hasn’t been any interest in it yet, so I’ve prioritized other highly requested things.

In the meantime, I would also note that you can create Virtual Buttons in Homey and use those in SharpTools to trigger your flows:

Thank You for advice.
Its work perfekt
Alex

1 Like

6 posts were split to a new topic: Customizing a Custom Tile?

Hi Josh!
This is great stuff.
Im using Homey Ink token solution with this Homey Image viewer. The devise has 3 different images associated with it. Is it possible to change the display of the first image to one of the other images instead? If so, how?
Many thanks,
Sanny

If the device stores the additional images as URLs in different capabilities, then you should just need to set the Capability ID field with the appropriate value.

Finding the Capability

Homey Image Viewer: Configuration Instructions

Hi,
I am trying to modify the chart settings (JSON) for the Google gauge, but I cant seem to get it to work. Could you post an example of how you do this? I am using a Homey (early 2019) with Homey Ink token.

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