Tutorial: Automatically Reload Dashboard After Remote Changes

Premise

So a Feature Request and another question have been submitted to these forums about wanting dashboards to be automatically refreshed when a change is made from a different window. Normally this notification is shown:
image

Well, the various solutions either didn’t work, or I wasn’t happy with so I made something else that’s a little more targeted.

Personally, I have some “kiosks” around my home displaying security cameras, and a few states. I want to make changes on my desktop and have them automatically applied to them all.

I wanted to do the following.

  • Only monitor dashboard pages
  • do not use timers in the event some other issue causes the browser to load slower than usual
  • be a set-and-forget solution.

Step by Step

Custom JS

Create a custom js file to hold the code:

vim www/custom-reloader.js

and populate it with the following:

custom-reloader.js
function waitForElement(root, selector) {
    return new Promise((resolve) => {
        if (root.querySelector(selector)) {
            return resolve(root.querySelector(selector));
        }

        const observer = new MutationObserver(() => {
            if (root.querySelector(selector)) {
                observer.disconnect();
                resolve(root.querySelector(selector));
            }
        });

        observer.observe(root, {
            childList: true,
            subtree: true,
        });
    });
}

function waitForNMElement(root) {
    waitForElement(root.renderRoot, "notification-manager").then((element) => {
        element = element.renderRoot.querySelector("ha-toast");
        // console.log("Toast Created:", element);
        if (
            element.__labelText ===
            "Your dashboard was updated. Refresh to see changes?"
        ) {
            location.reload(true);
        }
    });
}

// Only monitor dashboard pages
if (window.location.href.includes("lovelace")) {
    // console.log("This is a dashboard page");
    waitForElement(document, "home-assistant").then((element) => {
        // console.log("home-assistant created", element);
        waitForNMElement(element);
    });
}

You may need to change the ownership of the file depending on your setup.
You can do something like ls -la to get the user and group then a chown someuser:someuser www/custom-reloader.js

Home Assistant Configuration

Next edit the main Home Assistant configuration to use the custom js

# . . .
frontend:
    themes: !include_dir_merge_named themes
    extra_module_url:
        - /local/custom-reloader.js
# . . .

And finally, restart Home Assistant.

Notes

  • I’m not an experienced js dev, and a lot of googling and trial and error make up this solution. I left console.log(...) comments in there to explain my reasoning.

  • If you wanted to only monitory certain dashboards, you can change lovelace to a prefix so only dashboards with it in the slug will be applied.

. . .
window.location.href.includes("kiosk-")
. . .

Then urls like ha.example.com/lovelace/kiosk-office would be targeted.

You can apply such a prefix by opening the dashboard editor, clicking the orange pencil in the tab bar, and adding the desired slug into the “URL” field.

  • The script will not work if you manually change dashboards. For example, if I go to /lovelace/kiosk-office in a new browser tab, the script will work. If I manually change to the dashboard “Kiosk Front”, it will not. To get “Kiosk Front” to work, you need to manually refresh the page.

Hopefully this helps someone. If any more experienced individuals have code improvements, I can test and edit this post accordingly.

1 Like