天天看點

指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語

快來試一試吧

  • 背景介紹
    • 引言
    • 運作環境
  • 如何擷取硬體資訊
  • Command line Sensor(重點)
    • CPU 溫度示例(★)
      • 注意事項
    • 監控所有的失敗登入
    • 從遠端檔案擷取數值
    • 解析 JSON 資料(★)
      • 注意事項
    • 階段成果
  • Template Sensor(重點)
    • 配置
    • 階段成果
  • 基本完工
    • 分組
    • 未來工作
  • 通過 ESPHome 在 OLED 上顯示
  • 結語

背景介紹

引言

我們知道在 Home Assistant 中,

sensor

平台的作用就是擷取各種資料,但是有時候我們想要的裝置或特殊的資料,HA 并沒有指定的

platform

支援,是以 HA 給我們提供了一個強大的 Command line Sensor(指令行傳感器)平台。它可以通過指定的指令擷取資料,也就意味着幾乎可以接入 HA 任何種類的(包括具體的和抽象的)傳感器。 下面本文就帶你一步步手撸一個自己的傳感器出來~

指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語

運作環境

樹莓派 3B+ 在 Docker 下安裝 Hassio,使用

Samba

add-on,在 VS Code 中使用

Home Assistant Config Helper

插件編輯 YAML 檔案。

如何擷取硬體資訊

這裡以 epsilon1 的文章為參考,修改了一部分以适應 HA 的要求,運作環境為 Python3。不同的平台(這裡是樹莓派),可能相應的需要做出一些修改。

  • 注意: 在 Docker 内、外運作相同的指令,如擷取 CPU 和記憶體使用情況,會得到不同的結果(沒有學習過 Docker,直覺認為在 Docker 内外還是有差異的),是以以下腳本中注釋了使用者空間占用 CPU 百分比的資訊。
import os
import json

# Return CPU temperature as a float
def getCPUtemperature():
    f = os.popen("cat /sys/class/thermal/thermal_zone0/temp")
    temp = int(f.readline().strip())/1000
    return round(temp, 1)

# Return RAM information (unit=MB) in a list
# Index 0: total RAM
# Index 1: used RAM
# Index 2: free RAM
def getRAMinfo():
    f = os.popen("free | awk '/Mem/ {print $2,$3,$4}'")
    info = f.readline().split()
    info = [round(int(i)/1024, 1) for i in info]
    return info

'''
# Return % of CPU used by user as float
def getCPUinfo():
    # Docker外部 info = os.popen("top -n1 | awk '/Cpu\(s\):/ {print $2}'").readline().strip()
    # Docker内部 info = os.popen("top -n1 | awk '/CPU:/ {print $2}'").readline().strip()
    if info:
        return float(info)
    else:
    	# 未擷取到資訊,傳回預設錯誤值
        return -1.0
'''

# Return information about disk space as a list (unit included)
# Index 0: total disk space
# Index 1: used disk space
# Index 2: remaining disk space
# Index 3: percentage of disk used
def getDiskinfo():
    f = os.popen("df -h /")
    info = f.readlines()[1].split()[1:5]
    return info

if __name__ == '__main__':
    RaspiInfo = {}
    RaspiInfo['CPUtemp'] = getCPUtemperature()
    RaspiInfo['RAMinfo'] = getRAMinfo()
    RaspiInfo['DISKinfo'] = getDiskinfo()
    #RaspiInfo['CPUuse'] = getCPUinfo()
    # 必須轉化為标準 JSON 格式備用,下文有解釋
    print(json.dumps(RaspiInfo))
           

運作列印出的資料示例:

{"CPUtemp": 44.0, "RAMinfo": [874.5, 340.4, 37.7], "DISKinfo": ["15G", "8.5G", "5.3G", "62%"]}

Command line Sensor(重點)

廢話不多說,下面就來看看這個指令行傳感器如何配置吧!完整配置資訊請參考官方文檔 Command line Sensor ,下面摘錄一部分作主要說明。

CPU 溫度示例(★)

許多關于硬體的資訊可以由

proc

檔案系統獲得,這裡展示擷取 CPU 溫度的方法。

# configuration.yaml 示例,僅用于學習配置指令行傳感器,并不是本次項目的配置檔案
# 在 sensor 域下添加
sensor:
  # 平台名,不用多說
  - platform: command_line
	# 添加傳感器實體 entity 的名稱,引用時為 sensor.cpu_temperature,可在 開發者工具-狀态 内看到
    name: CPU Temperature
    # 用于擷取溫度資料的指令,注意單、雙引号的使用
    command: "cat /sys/class/thermal/thermal_zone0/temp"
    #(可選)傳感器資料的機關
    unit_of_measurement: "°C"
    #(可選)定義一個模闆,從 command 傳回的載荷資料(用 value 代替)中提取需要的值,
    # 若未定義模闆,則直接将 command 傳回的資料作為傳感器的值。
    value_template: '{{ value | multiply(0.001) | round(1) }}'
    #(可選)更新間隔,預設為 60s
    scan_interval: 60
    #(可選)指令執行逾時設定,預設為 15s
    command_timeout: 15
           

注意事項

  • 擷取指令的 command 直接将載荷資料 輸出、列印出來 即可,即類似于上面的

    cat

    指令;或者 Python 的

    print

    函數,可以看到在上一節擷取硬體資訊的腳本中,最後是一行列印函數

    print(json.dumps(RaspiInfo))

    。至于這裡為什麼要用

    json.dumps()

    我們後面再介紹。
  • 若使用 value_template 提取資料,則在模闆表達式中使用

    value

    代替指令輸出的載荷資料,而變量

    value_json

    則可以代替經 JSON 格式解析後的資料,具體的使用請參考文檔 Processing incoming data。

下面再通過幾個例子感受一下上面說的内容:

監控所有的失敗登入

# configuration.yaml entry 示例
sensor:
  - platform: command_line
    name: badlogin
    command: "grep -c 'Login attempt' /home/hass/.homeassistant/home-assistant.log"
           

從遠端檔案擷取數值

使用 Python 的 requests 庫,通過 HTTP 擷取指定 URL 的内容作為傳感器的數值。

可以學習一下這裡的

python3 -c "xxxxx"

通過指令行方式執行 Python 腳本的方式。

sensor:
  - platform: command_line
    command: python3 -c "import requests; print(requests.get('http://remote-host/sensor_data.txt').text)"
    name: File value
           

同樣可以執行外部的腳本,如下:

sensor:
  - platform: command_line
    name: Brightness
    command: "python3 /path/to/script/arest-value.py"    
           

解析 JSON 資料(★)

好了,當你大緻熟悉了這個指令行傳感器怎麼配置後,我們再來介紹它剩下的一個強大的功能:

(可選)json_attributes

。在這個配置選項下,我們定義一系列字典的鍵(Key),這樣指令行傳感器就能根據這些鍵名,從指令傳回的 JSON 字典資料中提取鍵對應的值,并将其設定為傳感器的屬性。這樣一來,我們就能一次性傳回多個數值了,非常友善。

  • 注意:傳回的字典一定要是符合标準 JSON 格式的,是以在上面的腳本中,最後一行利用了 Python 庫函數

    json.dumps()

    對字典進行 JSON 格式的編碼。最後列印出的資料示例如:

    {"CPUtemp": 44.0, "RAMinfo": [874.5, 340.4, 37.7], "DISKinfo": ["15G", "8.5G", "5.3G", "62%"]}

根據以上字典内容,我們在配置檔案的

sensor

域下添加:

# 我是在 configuration.yaml 中添加了一行 sensor: !include sensor.yaml
# 是以以下是 sensor.yaml 檔案的内容
- platform: command_line
  name: RaspInfo
  scan_interval: 60
  command: "python3 /config/scripts/queryRaspi.py" # 腳本路徑問題參考下面注意事項
  json_attributes: # 鍵名可為大小寫
  - RAMinfo
  - DISKinfo
  - CPUuse
  - CPUtemp
           

注意事項

  • 當執行外部腳本時,腳本的存放路徑顯得格外重要。如果是在 Docker 下安裝的 Hassio,腳本路徑應該寫為

    command: "python3 /config/scripts/queryRaspi.py"

    ,而不能用絕對路徑

    command: python3 "/usr/share/hassio/homeassistant/scripts/queryRaspi.py"

    ,會出現找不到檔案或目錄的錯誤。
    指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語
    指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語
    指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語
  • 而其他方式安裝的 HA,我沒有驗證過,配置中應該就是寫腳本的絕對路徑,至少官方文檔中示例寫的就是絕對路徑(如

    command: 'python3 /home/pi/.homeassistant/scripts/datetime.py'

    ),大家試一下會不會報錯吧。
  • 事實上,在我這種安裝環境下(Docker + Hassio),在 Samba 中看到的

    config

    目錄下的内容,和 Hassio 配置檔案的預設路徑

    /usr/share/hassio/homeassistant

    下的内容是一樣的。
    指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語
  • 是以,現在就把上面查詢樹莓派各種資訊的 Python 腳本儲存到

    config

    目錄下(也就是

    /usr/share/hassio/homeassistant/scripts/queryRaspi.py

    指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語

階段成果

至此,重新啟動 Home Assistant 服務後(你也可以在後面所有配置完成後再重新開機),我們将在 開發者工具-狀态 裡看到我們定義的一個指令行傳感器實體。

指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語
  • 可以看到實體名稱就是我們定義的

    RaspInfo

    的小寫

    raspinfo

    ;相應的,若取名為

    Rasp Info

    ,實體名稱就會變為

    rasp_info

  • 狀态(States)欄已經獲得了腳本指令正确的傳回值,并且屬性(Attributes)欄裡已經成功将字典裡的鍵(Key)解析為這個實體的屬性。

以上都沒有問題的話,我們繼續往下看。

Template Sensor(重點)

雖然上面的指令行傳感器已經能夠将(一整項)狀态資料顯示在首頁了,但是該怎麼把各項資料單獨作為傳感器實體顯示出來呢?事實上

template

平台支援我們定義一個從其它實體擷取值的傳感器,也就是

Template Sensor

,而這正是我們想要的功能(利用指令行傳感器的各個屬性值)。

下面就來看看這個基于模闆的傳感器如何配置吧!完整配置資訊請參考官方文檔 Template Sensor 。

  • 注:這一部分主要涉及的是模闆(template)的使用,這裡不作贅述,可以參考文檔 Templating

配置

在配置檔案的

sensor

域下添加:

# 我是在 configuration.yaml 中添加了一行 sensor: !include sensor.yaml
# 是以以下是 sensor.yaml 檔案的内容

# 平台名稱
- platform: template
  # 傳感器清單
  sensors:
    # 實體名稱:小寫,下劃線
    cpu_temp:
      # (可選)在前端顯示的傳感器昵稱
      friendly_name: "CPU Temperature"
      # (可選)傳感器數值的機關
      unit_of_measurement: '℃'
      #(必須)定義一個擷取傳感器狀态(數值)的模闆
      # 這裡就是擷取上面定義的指令行傳感器實體 sensor.raspinfo 的相應屬性值,注意大小寫
      value_template: "{{state_attr('sensor.raspinfo', 'CPUtemp')}}"
    # 以下配置類似,不再贅述
    ram_total:
      friendly_name: "RAM total"
      unit_of_measurement: 'MB'
      value_template: "{{state_attr('sensor.raspinfo', 'RAMinfo')[0]}}"   
    ram_used:
      friendly_name: "RAM used"
      unit_of_measurement: 'MB'
      value_template: "{{state_attr('sensor.raspinfo', 'RAMinfo')[1]}}"
    ram_free:
      friendly_name: "RAM free"
      unit_of_measurement: 'MB'
      value_template: "{{state_attr('sensor.raspinfo', 'RAMinfo')[2]}}"   
    disk_total:
      friendly_name: "DISK total"
      value_template: "{{state_attr('sensor.raspinfo', 'DISKinfo')[0]}}"
    disk_used:
      friendly_name: "DISK used"
      value_template: "{{state_attr('sensor.raspinfo', 'DISKinfo')[1]}}"
    disk_left:
      friendly_name: "DISK left"
      value_template: "{{state_attr('sensor.raspinfo', 'DISKinfo')[2]}}"      
    disk_percentage:
      friendly_name: "DISK percentage"
      value_template: "{{state_attr('sensor.raspinfo', 'DISKinfo')[3]}}"         
           

注意:這裡配置的比較精簡(足夠用了,實在是太累了,不想再打字了,而且官方文檔也很清晰),完整配置資訊請參考官方文檔 Template Sensor ,要學會模闆(template)的使用。

階段成果

至此,重新啟動 Home Assistant 服務後(你也可以在後面所有配置完成後再重新開機),我們将在 開發者工具-狀态 裡看到所有剛剛建立的傳感器的單獨實體。

  • 若在前端首頁出現實體不可用的警告或者玄學問題,可以嘗試重新啟動 Home Assistant 服務并注意觀察日志資訊
    指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語

基本完工

分組

最後隻需要簡單的分組即可:

# 我是在 configuration.yaml 中添加了一行 group: !include groups.yaml
# 是以以下是 groups.yaml 檔案的内容
default_view:
  view: yes
  icon: mdi:home
  entities:
    - group.raspinfo

raspinfo:
  name: 樹莓派
  control: hidden
  entities:
    - sensor.cpu_temp
    - sensor.ram_total
    - sensor.ram_used
    - sensor.ram_free
    - sensor.disk_total
    - sensor.disk_used
    - sensor.disk_left
    - sensor.disk_percentage
           

至此,重新啟動 Home Assistant 服務後(若前面已經重新開機過,這裡隻需要重載分組即可),在前端面闆便出現了各項傳感器資訊:

指令行傳感器和模闆的使用之在 Home Assistant 中監控樹莓派的 CPU 溫度,記憶體等資訊背景介紹如何擷取硬體資訊Command line Sensor(重點)Template Sensor(重點)基本完工通過 ESPHome 在 OLED 上顯示結語

Bingo !

未來工作

  • 完整閱讀文檔,了解所有配置(有個印象,友善查閱)
  • 對着文檔,修改傳感器圖示使得更加美觀
  • … … …

通過 ESPHome 在 OLED 上顯示

待填坑

結語

不知不覺寫了好長時間将近九千個字(符),太長不看系列。希望自己把問題描述的足夠清楚了,在這裡也隻是抛磚引玉,有了這一遍流程,大家就已經可以自己動手開發自己想要的各類“傳感器”了,别忘了來分享喔。