找回密码
 立即注册

微信扫码登录

搜索
查看: 5441|回复: 17

[技术探讨] [讨论] 如何在HA里编写重复性高且容易维护的配置代码?

[复制链接]

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
发表于 2022-8-13 00:22:43 | 显示全部楼层 |阅读模式
本帖最后由 relliky 于 2023-1-11 21:09 编辑

现阶段自动化的配置主要的代码都是yaml,但有很多重复代码,有一些逻辑给一个房间改了,就得给其他房间也再改一遍。毕竟不是所有的代码都可以放到可以重复利用的脚本script里面。这个时候,蓝图blueprint的优势就显现了出来。如果把蓝图比作面对对象语言里的类,而用蓝图代入参数后生成的自动化是一个实例的话,蓝图的局限性就在于这个类最大就只能是一条自动化。而HA自带的模板jinja连个自动化都模板不了,只能支持模板一个entity的代码。

因为家里有三个卧室,我更想把这个类扩大成一个房间的类,然后给它放入每个房间具体的参数,生成每个房间的实例,这个实例就是这个房间的package,还是以自动化为主,包括其他的部分像groups/scripts/template之类的也可以。举个例子,我的其中一个主卧厕所的yaml文件长这样:https://github.com/relliky/Tais_Home_Assistant_Config/blob/8caf667533f6337fe7f5159eb9015336cd86f5c6/packages/rooms/master_toilet.yaml

我设想的文件结构会是类似于这样的:
render_room_package.py
template/base_bedroom.yaml.templ
room_config/master_room.conf
room_config/guest_room.conf
room_config/en_suite_room.conf
auto_generated_packages/master_room.yaml
auto_generated_packages/guest_room.yaml
auto_generated_packages/en_suite_room.yaml


template里面包含每种房间的模板(类),room_config里面包含每个房间的参数,auto_generated_packages的就是每个房间的package yaml文件(实例化)。只有这些yaml文件会被HA读取,HA不读取templ和conf文件。现在就只想到了这里,大家有没有更好的方法去维护相似的代码呢?我知道pyscript不能实例化package,也只能实例化脚本和自动化。不知道node-red,appdaemon或者其他的工具可不可以。
-------------------------------------------------------EDIT: 20/08/22------------------------------------------------------------------------------------------------
受各位大神启发,用Python加PyYaml搞定了。用python写的模板然后用PyYaml输出。

至于如何迁移现有的yaml文件,大致就是先用PyYaml把现有的yaml读进python,打印出来,弄成python描述directory的python语言,修改一下把里面的可变量加进去变成模板,最后再生成出各个房间的yaml。

-------------------------------------------------------EDIT: 11/01/23------------------------------------------------------------------------------------------------

现在基本结构已经完成

render_room_package.py
template/base_bedroom.yaml.templ
room_config/master_room.conf
room_config/guest_room.conf
room_config/en_suite_room.conf
被合并成一个python文件,用面对对象的思路代替了上面的conf文件,给每个房间直接生成了一个新的类
https://github.com/relliky/Tais_ ... /gen_config_yaml.py

然后生成了13个自动化配置文件
https://github.com/relliky/Tais_ ... _generated_packages
和1个仪表盘配置文件
https://github.com/relliky/Tais_ ... c76c9fc015/lovelace

我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-20 07:40:58 | 显示全部楼层
coderwj 发表于 2022-8-14 22:28
后面有时间整理整理再考虑开源吧,目前ha部分代码不多,还没有放到单独的项目里

上面提到的三个类,放在 ...

受各位大神启发,用Python加PyYaml搞定了。用python写的模板然后用PyYaml输出。

至于如何迁移现有的yaml文件,大致就是先用PyYaml把现有的yaml读进python,打印出来,弄成python描述directory的python语言,修改一下把里面的可变量加进去变成模板,最后再生成出各个房间的yaml。
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-15 04:44:48 | 显示全部楼层
coderwj 发表于 2022-8-14 22:28
后面有时间整理整理再考虑开源吧,目前ha部分代码不多,还没有放到单独的项目里

上面提到的三个类,放在 ...

感谢感谢,受益匪浅
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

0

主题

22

回帖

127

积分

注册会员

积分
127
金钱
105
HASS币
0
发表于 2022-8-14 22:28:04 | 显示全部楼层
本帖最后由 coderwj 于 2022-8-14 22:46 编辑
relliky 发表于 2022-8-14 16:14
厉害厉害,这也给我提供了一个新的思路。大神有机会把代码开源吗?

后面有时间整理整理再考虑开源吧,目前ha部分代码不多,还没有放到单独的项目里

上面提到的三个类,放在附件中了,可以下载下来查看




ha.zip

2.65 KB, 下载次数: 1

生成配置文件相关的源码

回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-14 16:14:51 | 显示全部楼层
coderwj 发表于 2022-8-14 11:01
我是Java和groovy混编,目前只写了Sensor的

类 ServerInfo 是一个传感器属性的类,在字段里填充服务器的 ...

厉害厉害,这也给我提供了一个新的思路。大神有机会把代码开源吗?
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

0

主题

22

回帖

127

积分

注册会员

积分
127
金钱
105
HASS币
0
发表于 2022-8-14 11:16:16 | 显示全部楼层
本帖最后由 coderwj 于 2022-8-14 11:20 编辑
relliky 发表于 2022-8-14 05:37
具体怎么弄的能说说吗?

1. 下面是代码片段

    void init() {
        println("--------------- add sensor to configure.yaml ----------------------")
        // 固定的前缀
        println(
                """mqtt:
    sensor:
    # ${serverConf.user}.${serverConf.name}""")
        // 反射各字段, 转为yaml
        ServerInfo.getDeclaredFields().each { toSensorYaml(it) }
        println("\n------------------------------------------------------------------")
    }

    void toSensorYaml(Field field) {
        // 获取传感器的各属性的值
        def name = field.getName()

        def haSensor = field.getAnnotation(HaSensor)
        if (haSensor?.ignore()) {
            // 配置了ignore就忽略该字段
            log.debug("skip sensor ${name}")
            return
        }

        def serverName = serverConf.getName()
        def user = serverConf.getUser()
        def friendlyPattern = haSensor?.friendlyName() ?: haSensor?.value()
        def friendlyName = friendlyPattern ? friendlyPattern.formatted(serverName) : "${serverName} ${name}"
        def uniqueId = "${serverName}_${StringUtil.camelToUnderline(name, false)}"

        // 统一加到variables集合,key为ha中sensor的字段名,value为字段值
    // def variables = [:] 下面一行应该是这个, 论坛好像会把行尾的 [ : ] 转义
    def variables = [:

        // 实体名称
        variables."name" = "${friendlyName}"
        variables."state_topic" = "home/${user}/${serverName}/sensor/info"
        // 实体id?
        variables."unique_id" = uniqueId
        variables."object_id" = uniqueId
        variables."value_template" = "{{ value_json.${name} }}"

        def icon = haSensor?.icon() ?: (homeConf.icon ?: "")
        if (icon) {
            variables."icon" = icon
        }

        def expireAfter = haSensor?.expireAfter()
        if (expireAfter) {
            variables."expire_after" = expireAfter
        }

        def unit = haSensor?.unitOfMeasurement()
        if (unit) {
            variables."unit_of_measurement" = unit
        }

        // 遍历variables拼接sensor字段
        def sensor = ""
        variables.each { it ->
            def pre = it.key == "name" ? "    - " : "      "
            sensor += "${pre}${it.key}: \"${it.value}\"\n"
        }
        print(sensor)
    }







2. 输出效果如下

--------------- add sensor to configure.yaml ----------------------
mqtt:
  sensor:
    # me.pc
    - name: "pc 设备名"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_name"
      object_id: "pc_name"
      value_template: "{{ value_json.name }}"
      icon: "mdi:desktop-tower-monitor"
    - name: "pc 设备别名"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_alias"
      object_id: "pc_alias"
      value_template: "{{ value_json.alias }}"
      icon: "mdi:desktop-tower-monitor"
    - name: "pc 操作系统"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_os"
      object_id: "pc_os"
      value_template: "{{ value_json.os }}"
      icon: "mdi:microsoft-windows"
    - name: "pc 启动时间"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_boot_time"
      object_id: "pc_boot_time"
      value_template: "{{ value_json.bootTime }}"
      icon: "mdi:clock-time-two"
    - name: "pc ip"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_ip"
      object_id: "pc_ip"
      value_template: "{{ value_json.ip }}"
      icon: "mdi:ip-network"
    - name: "pc CPU型号"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_cpu_type"
      object_id: "pc_cpu_type"
      value_template: "{{ value_json.cpuType }}"
      icon: "mdi:cpu-64-bit"
    - name: "pc CPU占用率"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_cpu_used"
      object_id: "pc_cpu_used"
      value_template: "{{ value_json.cpuUsed }}"
      icon: "mdi:cpu-64-bit"
      expire_after: "60"
      unit_of_measurement: "%"
    - name: "pc 内存占用信息"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_mem_used_info"
      object_id: "pc_mem_used_info"
      value_template: "{{ value_json.memUsedInfo }}"
      icon: "mdi:memory"
      expire_after: "60"
    - name: "pc 内存占用率"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_mem_used"
      object_id: "pc_mem_used"
      value_template: "{{ value_json.memUsed }}"
      icon: "mdi:memory"
      expire_after: "60"
      unit_of_measurement: "%"
    - name: "pc 风扇速度"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_fan_speed"
      object_id: "pc_fan_speed"
      value_template: "{{ value_json.fanSpeed }}"
      icon: "mdi:fan"
      expire_after: "60"
    - name: "pc 温度"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_temperature"
      object_id: "pc_temperature"
      value_template: "{{ value_json.temperature }}"
      icon: "mdi:car-brake-temperature"
      expire_after: "60"
      unit_of_measurement: ""
    - name: "pc 状态刷新时间"
      state_topic: "home/me/pc/sensor/info"
      unique_id: "pc_last_modify"
      object_id: "pc_last_modify"
      value_template: "{{ value_json.lastModify }}"
      icon: "mdi:clock-time-two"

------------------------------------------------------------------






评分

参与人数 1金钱 +5 收起 理由
relliky + 5 高手,这是高手!

查看全部评分

回复

使用道具 举报

0

主题

22

回帖

127

积分

注册会员

积分
127
金钱
105
HASS币
0
发表于 2022-8-14 11:01:24 | 显示全部楼层
relliky 发表于 2022-8-14 05:37
具体怎么弄的能说说吗?

我是Java和groovy混编,目前只写了Sensor的

类 ServerInfo 是一个传感器属性的类,在字段里填充服务器的状态信息,每一个字段都对应一个ha的sensor传感器

自定义注解 @HaSensor 可以压在传感器属性类(比如 SenverInfo)的字段上,描述当前字段(传感器)的可选属性,比如别名,图标,过期时间,单位等

之后程序初始化的时候,反射 传感器类ServerInfo 获取各字段(传感器),如果有注解的话,还会获取注解的值来初始化传感器的可选信息

有了这些信息之后,就可以通过模板代码来输出ha能识别的yaml了
回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-14 05:41:23 | 显示全部楼层
blindlight 发表于 2022-8-14 01:03
能的 创什么都可以 你新建个根本没有的integrate都没问题

感谢感谢,我去学习一下。
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-14 05:40:01 | 显示全部楼层

pyscript只能搞自动化和脚本。
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-14 05:38:42 | 显示全部楼层
ryanh7 发表于 2022-8-13 20:47
抽象能力对普通用户来说基本是个不可能的事,而对于会编程的人来说有一百种方法。 ...

哈哈哈,一针见血。我就想看看有没有人前人栽树,可以少走点弯路~
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

33

主题

1118

回帖

5522

积分

论坛元老

积分
5522
金钱
4356
HASS币
90
 楼主| 发表于 2022-8-14 05:37:33 | 显示全部楼层
coderwj 发表于 2022-8-14 00:39
是个好思路, 我现在是用代码生成yaml再复制进去

具体怎么弄的能说说吗?
我家全屋智能的HA设置 https://github.com/relliky/Tais_Home_Assistant_Config
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian ( 晋ICP备17001384号-1 )

GMT+8, 2025-9-5 14:20 , Processed in 1.366057 second(s), 8 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表