天天看点

命令行传感器和模板的使用之在 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 上显示

待填坑

结语

不知不觉写了好长时间将近九千个字(符),太长不看系列。希望自己把问题描述的足够清楚了,在这里也只是抛砖引玉,有了这一遍流程,大家就已经可以自己动手开发自己想要的各类“传感器”了,别忘了来分享喔。