缘起
虽然新能源汽车越来越普及,但是就目前而言,传统的燃油车仍然是占比最高的车型。因此,每次油价的调整自然会备受车主的关注。
由于平时懒得打开App查看油价,所以每次加油时才会看一眼加油站的标价。因此,其实本人对汽油的价格并不感冒。但是,最近一直在“折腾”Home Assistant,脑海中浮现的想法都是围绕着它展开,于是就想到了用Home Assistant来跟踪油价的变化。
需求
首先,汽油的价格能够被实时获取,并且获得的数据能够被存储到Home Assistant中。当汽油的价格发生变化时,例如上涨或者下跌,Home Assistant可以发送通知到本人的手机。
数据源
在网上查找了一下关于汽油价格的网站,发现以下网站的信息比较全面,并且提供的油价可以精确到区级。
下面以上海为例,访问的网址是: http://www.qiyoujiage.com/shanghai.shtml ,网页的部分源代码如下:
<dl> <dt> <dd>是HTML中的一套组合标签,可以用于制作网页中的表格。
<div id="youjia"> |
Beautiful Soup
Beautiful Soup
是一款非常著名的Python第三方库,可以用来解析HTML文本,且非常简单易用。
首先,用Requests
获取网页的内容,并将返回的结果存储到response
变量。
import requests |
用Beautiful Soup
来解析网页内容(response.content
),先查找所有dl
标签,然后用for
循环语句迭代每一个dl
标签的内容,如果找到关键字92
,就结束循环,并返回name
和price
。
为了便于Home Assistant处理脚本返回的值,此处最终结果以JSON字符串的格式输出。
format_string = '%Y-%m-%d %H:%M:%S' |
运行以上代码,就会得到下面的结果:
{"name": "上海92#汽油", "price": 7.34, "last_update": "2024-09-28 12:33:01"} |
Command Line
打开并编辑Home Assistant的配置文件configuration.yaml
,添加传感器的配置内容。
command_line: |
配置参数说明:
name 传感器的名称
command 需要执行的命令或者脚本
json_attributes 传感器的属性,此处有两个属性:name和last_update
value_template 获取命令或者脚本返回的值
device_class 实体的类型,Home Assistant会根据设置的类型,在Dashboard中适配相应的图表
unit_of_measurement 值的单位
scan_interval 执行脚本的时间间隔,默认单位为“秒”
command_timeout 命令或者脚本默认15秒后超时,此处设置为60秒
完成以上配置,并重载命令行配置以后,在Home Assistant中就会新增一个实体,该实体的标识符为sensor.shang_hai_92_you_jie
。
该实体的状态属性如下:
name: 上海92#汽油 |
油价涨跌变化
为了能跟踪油价的涨跌变化,并且可以在第一时间接收到关于油价涨跌的信息,需要根据油价在发生变化前后的比较,来判断油价的涨跌。
弯路: 根据文档automation | trigger state,自动化的触发器可以提供触发前后的数据:trigger.from_state
和trigger.to_state
,但是实际测试过程中,发现如果触发器是基于状态(state)的变化,而不是数值区间(numeric_state)的变化,则无法在消息通知中通过jinja
模板来进行数值对比。
因此,我决定通过执行脚本来反映油价的涨跌情况。那么,如何在脚本中获取油价变化前的数据呢?此时,我想到了用home assistant rest api。在获取最新油价之前,先从Home Assistant获取当前的油价信息。
from requests.packages.urllib3.exceptions import InsecureRequestWarning |
请将entity_id
换成实体的真实ID标识符。长期有效的Token需要在Home Assistant管理界面的个人配置文件中生成,具体可以参考文档:Authentication
previous_price = 0 |
因为用requests
访问API的时候会出现SSL证书错误的告警信息,且访问会失败,所以需要添加参数verify=Fales
,这样就不会对SSL证书进行检查。但是,仍然会打印告警信息。因此,还需要用以下方法关闭告警信息。
from requests.packages.urllib3.exceptions import InsecureRequestWarning |
通过以上代码,就获取到了油价变化前的价格previous_price
。
通过跟最新油价的比较,就可以判断油价的上涨和下跌。这样,油价传感器的属性又增加了一项price_changed
。
current_price = youjia_92['price'] |
自动化
trigger
当实体sensor.hui_shan_92_you_jie
的属性price_changed
值从N/A
变化成任何其它状态,自动化都会被触发。
trigger: |
action
自动化触发后,执行通知动作,将通知消息发送到目标手机,消息的标题是实体sensor.shang_hai_92_you_jie
的属性值price_changed
,消息的正文是自动化触发前的价格{{ trigger.to_state.state }}
和触发后的价格{{ trigger.from_state.state }}
。
action: |
手机上收到的通知消息见下图:
开发者工具
Home Assistant的开发者工具中有两项功能对于测试很有帮助,分别是:设置状态和动作。
设置状态
设置状态可以改变实体的状态值,例如,可以改变实体sensor.shang_hai_92_you_jie
的油价,这样就可以帮助测试自动化的运行结果是否正确。例如,真实油价是7.34,我们就可以将油价改成7.50,然后当传感器再次获取到真实油价的时候,就可以触发自动化的运行。
打开开发者工具,在状态中可以设置状态的选项。
动作
由于传感器只能根据设定的时间间隔更新数据,没有手动更新的选项。但是,测试时需要立即获取到最新的数据,这时可以用homeassistant.update_entity
来实现。
打开开发者工具,进入动作页面,进入YAML模式,输入以下内容,或者也可以在用户界面模式下操作。点击执行动作后,就会更新实体sensor.shang_hai_92_you_jie
。
action: homeassistant.update_entity |
参考资料
templating
jinja | templates
memory of previous state
automation | trigger state
manually refresh rest sensors
perform actions
Automation: template value should be a string for dictionary value @ data[‘value_template’]. Got None
home assistant rest api
# Python ‘requests’ Module: How to Disable Warnings