HomeAssistant与ESP32

 · 6 分钟
Table of contents

前言

因为突然对智能家居很感兴趣, 稍微 折腾了一下

Home Assistant

Home Assistant是一个用Python实现的开源智能家居平台,着眼于不依赖于云服务的离线智能家居。有赖于社区动力, 主流智能家居供应商的产品大多可接入Home Assistant管理。许多开源家居智能化方案也接入了Home Assistant。 就不过多介绍了。

Tasmota

简介

Tasmota是一个ESP32/ESP8266平台的开源固件,通过MQTT或HTTP API进行数据交互。 它将各个平台抽象为一系列模板,用统一的固件+硬件模板配置适配了各种各样的商业产品。 比如我手上的小米米家台灯1S,就可以刷成Tasmota固件。

通过其内置的三种脚本系统(rules,scripts,berry scripts)可以实现很多复杂的功能,例如 联机自动注册设备、自动上报数据、自动触发某一长时间运行的流程。

想在Home Assistant Core中接入Tasmota,只要自己搭建好MQTT服务器、启用MQTT和Tasmota集成, 再配置好Tasmota设备接入即可。

实例:Tasmota+人体传感器+HASS

鉴于很多传感器都不需要多少配置就能无缝整合入Home Assistant,这里介绍一个需要一点操作的案例。

人体传感器,简单版,参考下列资料

  • https://tasmota.github.io/docs/PIR-Motion-Sensors/
  • https://tasmota.github.io/docs/Rules/
  • https://www.home-assistant.io/integrations/mqtt

步骤概要:

  1. 配置Tasmota中检测信号的GPIO
  2. 配置Tasmota中对应的自动化规则
  3. 在Home Assistant中配置相关设备集成

首先是人体传感器信号检测。这里使用HLK-LD2410传感器,其支持已加入Tasmota 12.3.1,不过下面做的其实和所谓支持关系不大。 LD2410提供了一个OUT信号脚,在检测到人体时是高电平,一段时间未检测到人体后就变为低电平。将OUT与ESP32的某个GPIO (下称GPIOx)相连,在Tasmota配置页面进入 ConfigurationConfigure Module ,将对应的GPIOx设置为Switch,并分配一个闲置ID。 下面假设这个Switch的ID是1。

Note

Switch的ID无所谓,只要选空闲的就好。后面的指令需要将对应命令、Switch1等字串末尾的1改成对应ID。默认情况下,Switch会控制ID相同的灯。

进入 ConsolesConsole ,设置对应Switch模式,关闭其开关相同编号设备的作用,同时关闭开关对应的MQTT消息。

SwitchMode1 1
SwitchTopic 0

给Tasmota配置一个自动化规则,在信号发生变化的时候发送MQTT消息,在连接到MQTT服务时向Home Assistant注册该传感器。

rule1
 on Switch1#state=1 do publish stat/%topic%/PIR1 ON endon
 on Switch1#state=0 do publish stat/%topic%/PIR1 OFF endon
 on mqtt#connected do publish2 homeassistant/binary_sensor/presence_%deviceid%/config { "name": "Presence Sensor", "object_id": "presence_%deviceid%", "device_class": "presence", "state_topic": "stat/%topic%/PIR1"} endon

rule说明

rule有三个存储空间,分别为rule1、rule2、rule3。其中每个空间至少可以存储1000字节的指令,考虑到压缩,可能会更多。 rule1后面的1 不用 和对应开关的ID一致!

Note

在终端输入上述指令时注意合并成一行!

下面提供另外一种写法,不过根据配置不同,数据刷新可能不够及时

rule1
 on mqtt#connected do publish2 homeassistant/binary_sensor/presence_%deviceid%/config { "name": "Presence Sensor", "object_id": "presence_%deviceid%", "device_class": "presence", "state_topic": "tele/%topic%/SENSOR", "value_template": "{{ value_json.Switch1 }}"} endon

接下来启用rule1,保存配置并重启

rule1 1
restart 1

最后便可以在Home Assistant的实体注册表找到名为“Presence Sensor”的人体存在检测设备了。 通过复杂一点的脚本,还能实现人体动态与静态的检测,当然这就需要启用LD2410传感器对应的支持以利用串口数据了。

ESPHome

架构介绍

就我目前所知,ESPHome的设计大致如下:

  • 所有ESPHome设备的固件由一组ESPHome程序(Dashboard或CLI)根据给出的设备配置(YAML)生成
    • 算是一揽子服务(配合PlatformIO CLI)
    • 初见比较难hack
    • YAML解析有一些特殊语法
  • 每个ESPHome设备可以独立运行,不依赖面板/Dashboard
    • 面板只有UI/UX变了
    • CLI有提供指引系统,但是支持的开发板数量较少,如果一开始就要使用不支持的开发板会比较困难
    • 固件可以通过USB安装,HTTPS连接dashboard的情况下可以用Web USB给ESP32编程
  • Home Assistant通过约定的API接口与ESPHome设备交互数据,需要在设备配置YAML中写一行 api: 开启API

(不得不说这个项目的文档很不适合我,很难检索到所需的资料)

也就是说,ESPHome包括编译系统和边缘设备两部分。

使用Python虚拟环境准备ESPHome部署环境

鉴于官网已经花费了大量篇幅从一开始就为Home Assistant和Docker用户介绍了对应的使用方法,这里将 完整地介绍一遍不使用Docker、Home Assistant插件来使用ESPHome的流程。

前面说过,ESPHome把相关工作都包揽了,这里只需要构建一个虚拟环境作为工作空间就好。 构建虚拟环境可以使用下面的指令。

# 创建虚拟环境
python3 -m venv esphome-venv
# 激活虚拟环境
source esphome-venv/bin/activate

虚拟环境的pypi镜像与代理配置

可以直接在虚拟环境文件夹(上例中是 esphome-venv)内新建一个pip.conf,在其中添加对应配置,例如使用阿里云的pypi源:

[global]
index-url = https://mirrors.aliyun.com/pypi/simple/

[install]
trusted-host=mirrors.aliyun.com

接下来随意创建一个保存YAML的文件夹作为工作空间便可以了。

实例:使用LuatOS-CORE-ESP32C3开发板制作低功耗蓝牙(BLE)网关

参考了下列资料:

  • https://digiblur.com/wiki/ha/esphome-bluetooth-proxy-esp32c3/
  • https://esphome.io/components/display/index.html
  • https://esphome.io/components/display/st7735.html

激活虚拟环境,在你的配置保存文件夹内编写如下YAML,保存为 ble-gateway.yaml

substitutions:
  display_name: core-esp32c3-btproxy

esphome:
  name: ${display_name}
  platformio_options:
    board_build.mcu: esp32c3
    board_build.variant: esp32c3  

esp32:
  variant: ESP32C3
  board: esp32dev
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
      CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
      CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10"    

logger:
api:
ota:

button:
  - platform: safe_mode
    name: ${display_name} (Safe Mode)

# 记得改WiFi和密码
wifi:
  ssid: "Your SSID"
  password: "Your secret password"
  #manual_ip:
  #  static_ip: !secret ip_esp32c3_btproxy
  #  gateway: !secret ip_gateway
  #  subnet: !secret ip_subnet
  #  dns1: !secret ip_dns1

esp32_ble_tracker:
  scan_parameters:
# 可能需要调参
#    interval: 1100ms
#    window: 1100ms
    active: true

bluetooth_proxy:
  active: true

#### 下面是给显示器模块配置的 ###

# 五个按钮
# 由于 ESPHome 把 GPIO12、GPIO13强制占用了(原本控制Flash的),所以有一个按钮不能用。
binary_sensor:
  - platform: gpio
    name: "Up Button"
    pin:
      number: GPIO9
      inverted: true
      mode:
        input: true
        pullup: true
  - platform: gpio
    name: "Down Button"
    pin:
      number: GPIO5
      inverted: true
      mode:
        input: true
        pullup: true
 - platform: gpio
   name: "Left Button"
   pin:
     number: GPIO8
     inverted: true
     mode:
       input: true
       pullup: true
#  - platform: gpio
#    name: "Right Button"
#    pin:
#      number: GPIO13 # this pin is spared on CORE-ESP32C3
#      inverted: true
#      mode:
#        input: true
#        pullup: true
  - platform: gpio
    name: "Center Button"
    pin:
      number: GPIO4
      inverted: true
      mode:
        input: true
        pullup: true

# 显示器SPI
spi:
  clk_pin: GPIO2
  mosi_pin: GPIO3

# 来点显示的东西
# 可惜写这个的时间貌似还没支持
#time:
#  - platform: sntp
#    id: sntp_time
font: # 字体需要自己拷贝一份哦,下面是相对于该配置文件的位置
  - file: "fonts/iosevka-regular.ttf"
    id: my_font

# display ST7735
display:
  - platform: st7735
    model: "INITR_MINI160X80"
    reset_pin: GPIO10
    cs_pin: GPIO7
    dc_pin: GPIO6
    device_width: 80
    device_height: 160
    col_start: 0
    row_start: 0
    use_bgr: true
    lambda: |-
      it.print(0, 1, id(my_font), "Hello");
      it.print(0, 22, id(my_font), "World!");
      // it.strftime(0, 35, id(my_font), "%Y-%m-%d %H:%M", id(sntp_time).now());

接上设备,执行下面的命令刷机,就可以在Home Assistant里配置了。

esphome run ble-gateway.yaml --device=/dev/ttyACM0

Warning

记得先激活虚拟环境!