Home Assistant中利用iframe card將文字檔內容嵌入lovelace的方法

在前面Home Assistant的File Notify Service用法一文中提到了怎麼將日誌寫進檔案中,如果要把內容直接放上lovelace裡的話,比較常見的是建立一個command line sensor去取得檔案的內容,並且依照需求做過濾。比如檔案內容是這樣

Home Assistant notifications (Log started: 2024-09-27T06:30:28.644724+00:00)
--------------------------------------------------------------------------------
2024/09/27 14:30:28 → 維護模式開啟。
2024/09/27 14:30:31 → 維護模式關閉。
2024/09/27 14:43:56 → 主缸水位在交界處。
2024/09/27 14:44:13 → 維護模式開啟。
2024/09/27 16:55:05 → 維護模式關閉。
2024/09/27 16:55:41 → 主缸水位在交界處。
2024/09/27 16:58:41 → 主缸水位正常。

我只想保留最新10筆日誌並放在lovelace哩,command line sensor可以這樣做

- sensor:
    name: Aquarium_Log
    command: "tail -n +3 /config/www/aquarium/aquarium.txt | tail -n 10"

它會去讀取/config/www/aquarium/aquarium.txt的檔案,從第3行開始讀取,並留下倒數10行的內容。展開sensor.aquarium_log的內容如下

透過markdown card就可以把它放在lovelace裡

到這裡其實看起來也不是什麼問題,但Home Assistant Sensor有字元數的限制,日誌的總字元數如果超過255,sensor會變成unknown。

找了好一陣子,發現有同樣問題的人也不少,多個解決方案中我覺得比較全面的方式是用內嵌網頁的方式。做法是建立一個html檔案,在html檔裡利用javascript讀取文字檔的內容,再透過iframe card放在lovelace裡。這裡會有二個檔案

  • 原本的日誌檔,路徑與檔名為/local/aquarium/aquarium.txt,這裡的/local就是/config/www。
  • 新建立的html檔,路徑與檔名為/local/aquarium/aquarium.html,透過javascript讀取日誌檔並轉成html。

aquarium.html的內容如下,先去除頭2行,再固定顯示倒數40行的內容。

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body { font-family: Arial, sans-serif; }
        pre { white-space: pre-wrap; font-size: 14px; font-family: Arial, sans-serif; }
    </style>
</head>
<body>
    <pre id="logContent">Loading...</pre>
    <script>
        const cacheBuster = new Date().getTime();

        fetch(`/local/aquarium/aquarium.txt?cb=${cacheBuster}`)
            .then(response => {
                if (!response.ok) {
                    throw new Error('Network error: ' + response.statusText);
                }
                return response.text();
            })
            .then(data => {
                const lines = data.split('\n');
                const trimmedLines = lines.slice(2);
                const last40Lines = trimmedLines.slice(-40);
                const result = last40Lines.join('\n');
                document.getElementById('logContent').textContent = result;
            })
            .catch(error => {
                document.getElementById('logContent').textContent = 'Logging error: ' + error.message;
            });
    </script>
</body>
</html>

將/local/aquarium/aquarium.html用iframe card嵌入lovelace裡

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端