Display txt file content in frontend

I would like a better way to do this too (without having to create a sensor), but here is what I did (you seem to be close):

Created a sensor that gets is data from a text file, then get the state (data) from the sensor using a markdown card. The sensor and markdown seem to keep the same format, at least the multi-line

# meal sensor in configuration file
  - platform: command_line
    name: Meal
    command: 'cat /config/meal_sensor.txt'
# lovelace markdown card
type: markdown
content: |
  ## <ha-icon icon="mdi:food-variant"></ha-icon> &nbsp;Dinner Plans
  {{ states('sensor.meal') }}

Here’s what it looks like on the frontend:
image

6 Likes

This will only work for text files < 254 characters

2 Likes

I decided to make a ‘History of Events’, as in the Majordomo smart home platform. But I also ran into the problem described above ‘only works if the number of characters is below 255’.

Ideas appeared:

  1. Use attributes (since they seem to be not limited by the number of characters in the value of sensor). But I don’t know how to give the sensor across platform: command_line an attribute. It is also not clear how to change the attribute inside the finished sensor (attribute_templates?).
  2. Use card of webpage, storing data in html in www, wrapping data in html code for nice line wrapping, etc. But what the fuck … this card works through the ass and just does not update at all …
    Is it possible to somehow refresh the page, by some service or in another way? Since events are generated by automation / scripts, we can add something that will trigger a page refresh (loading data from a file) …

I’ve had the exact same problem. The card does not update because of web caching that HomeAssistant is doing. The only solution that I have come up with is running my own webserver where I can tell it not to do caching, and then point the webpage card to that link.

That’s quite a pain though for a simple thing, I’m still looking for a better solution.

1 Like

It is also an option. But I didn’t go that far, I added an update button to the html file, ignoring the cache, it works on a double click … I think you can also make an automatic update using a script.
We insert this into your html file (you can insert it, stupidly, in a line, or better put it into the ‘<body…’):

<!DOCTYPE html>
<html>
  <body>
    <button value="Refresh Page" onClick="JavaScript: location.reload(true)">Refresh</button>
1 Like

The caching occurs in the content card in the lovelace dashboard… which is understandable but super annoying. A yaml option to toggle this behavior on and off would be awesome.

The Workaround:
The way to bypass content caching is to use a dynamic query string and load content. Here’s how I do it for a few of my applications, and it works like a charm (almost the EXACT use case the OP is after).

Store your log content in a file in the WWW directory. HTML, text, whatever. For argument’s sake, let’s call it “log.txt” (warning, this data is accessible without authentication, beware…).

Use a different HTML file in WWW (let’s call it log.html) as your ‘webpage card’ embedded in the dashboard, with a javascript call in it to HTTP GET the log.txt and document.write() it out. The TRICK is to use a dynamic query string within the javascript GET call loading the other content. The query string is always different, so it bypasses the cache every time.

<html>
    <head>
        <title>TEST</title>
        <script>
function httpGet(theUrl)
{
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
    xmlHttp.send( null );
    return xmlHttp.responseText;
}

</script>
    </head>
    <body>
    Log Text: <script>document.write(httpGet("/local/log.txt?" + Date.now()));</script>    
        
    </body>
</html>

Hope that helps someone avoid a few gray hairs.

6 Likes

Just want to say thank you, this works great!

I’ve been trying to solve this problem for a couple of months.

2 Likes

i’m so happy i checked this and grateful that the forum has people that are reluctant and don’t give up.
I haven’t tried it yet, but the post and follow up just give me hope. Thanks again

1 Like

Thanks for this tip! I have one question: My file contains line breaks. How do I read the file, so that it displays the line breaks? Right now it shows everything in one line.

I’m not into HTML or javascript.

Di you mean the text on a new line? Then you need to save the data to your file as for html, that is, add < p></ p> (need to remove the space before ‘p’) every time for new line:
<p>Here is my text.</p>

Thank you, I did this with the help of txt2html in linux.

I just had to say thank you for your contribution. Your workaround was exactly what I was looking for. Thanks for making it possible.

really sorry, but how do we use the webpage card on a local file… could you please show me?

only use the card for external addresses, and they merely show the link, so this usage is new to me

I am using the html in www/html/daylight_settings.html, and content is is looking for in in /config/logging/filed_daylight_settings.txt.

upon loading I can see the Initial text string, but also see the HA icon we see when Ha is loading. After that, nothing is showing except for an empty card and my own menu shortcut bar, which I dont understand why that is showing at all…

    - type: iframe
      title: Daylight changes
      url: /local/html/daylight_settings.html

and string in the html:

</script>
    </head>
    <body>
    Daylight changes: <script>document.write(httpGet("/config/logging/filed_daylight_settings.txt?" + Date.now()));</script>

    </body>
</html>

edit

I managed to show the file by using the /local/filed_daylight_settings.txt and /local/ for the paths only. Can we not change those paths at all? seems a bit strange if that were the case.

Hello,

I am using this html script that works fine but since the file is having a lot of lines, does somebody know how to display directly the bottom of the file in the Web page card?
That will avoid to move the vertical scroll bar to the bottom to read the last input.

Thanks

I once made top-down and bottom-up navigation buttons using ready-made JS and CSS libraries, but since I am not a programmer and have little experience, I could not bring it to mind. Over time, demolished and sunk into oblivion…

How did you accomplish this?

Were you able to display the file in frontend?

Here is the solution I use for text file, convert the file into an html format using the following shell script (this shell script is adding a first line which is refreshing the link every 5 seconds !):

#
# program to convert a file into an html format
#

/config/private_shell_scripts/text2html.awk $1 > $2

sed  -i '1i<meta http-equiv="refresh" content="5">' $2

You can call this script into another shell to convert for example the output logfile into a html page. Here is an example:

/config/text2html.sh /config/rsync_mynas.log /config/www/rsync_mynas.html

The AWK procedure can be downloaded from this site:

https://vgoenka.tripod.com/unixscripts/text2html.html

The file can be displayed using a iframe card like this:

  type: iframe
  url: /local/rsync_mynas.html
1 Like

Thanks! That did the job for me.

I wanted to display text file content (actually, a selected set of recent lines from a log file) and couldn’t find an easy way to do this - and the accepted solution here didn’t do what I needed. I ended up using an http component. Posting here in case someone else finds it useful. See this github gist:

Display log file content in web frame

This is (potentially) brilliant. Thank you.

html isn’t my strong suit but I think I have trimmed it down to just output the txt file line by line with no extra formatting.

However, I’m getting 404 file not found?
(bluetooth_devices.txt is just a random file I’m using for testing)

Am I missing something obvious?

image


  - type: iframe
    url: /packages/Logging/my-log.html
    aspect_ratio: 100%
    title: Log File
<html>
    <meta http-equiv="refresh" content="60" />
    <head>
        <title>Log File</title>
        
        <script>

            // Read the logfile
            // - Returns up to "NumberOfEntries" lines
            // - Entries are returned in order determined by "Direction" parameter

            function GetTextfileLines(FileUrl, NumberOfEntries, Direction) {

                let xmlHttp = new XMLHttpRequest();
                xmlHttp.open( "GET", FileUrl, false );
                xmlHttp.send( null );
                let Lines = xmlHttp.responseText.split("\n");

                let LineCount = Lines.length;
                let LastLineIdx = LineCount -2;   // Last entry is displayed first. The last line of the file is blank, so subtract 2 to get last line index
                let FirstLineIdx =  Math.max(2, LineCount-NumberOfEntries-1);  // ...count backwards but stop before the header lines

                let FileString = "";   
                // let FileString = "<table><tr><th>Date</th><th>Event</th></tr>";   // Table with Header Row 
            
                if (Direction > 0) {
                    for (let i = FirstLineIdx; i <= LastLineIdx; i++) {
                        FileString += Lines[i];
                    }
                } else {
                    for (let i = LastLineIdx; i >= FirstLineIdx; i--) {
                        FileString += Lines[i];
                    }
                }

                return FileString;
            }

        </script>
    </head>

    <body>

        <script>

            // Read up to 10 most recent lines from the file
            document.write(GetTextfileLines("bluetooth_devices.txt", 14, 1));

        </script>

    </body>
</html>