HomeAssistant,打造智能家居

第 1 节 概述

现在,大家家中或多或少都会有一些有「智能家居」功能的电器,这些电器能够连网,并且配置好之后,可以使用专用的 App 远程控制。

示例

比如,在回家的路上,大约还有 10 多分钟到家,就可以远程控制家中的空调,提前打开。

当这些各式各样的电器多了以后,难免会遇到一些问题。主要的困扰在于,需要安装各式各样的 App ,这一过程十分繁杂。为了解决这一困扰,市场上出现了一些智能家居产品的集成商,比较知名的就是米家、天猫精灵和小度,只要购买与他们自家生产或者有合作关系的第一方产品,或者适配了他们平台的第三方产品,就可以使用他们提供的 App ,统一适配各种产品。

但是,这需要我们在购买之初就做好一些功课,选择可以适配的产品,这样会减少我们可以选择的余地。并且,可能我们已经购买了多个品牌的产品,并且近期并不需要更换,所以还是被迫要安装很多的 App。或者,也可能像本人这样,房子是租的,能用什么样的智能家居产品,取决于房东的选择。

那么,如果我们手头上已经有了一堆各式各样的产品,我们想要使用一个 App 去集中控制它们,并且我们希望各个产品之间可以形成联动,可以按照设定的逻辑自动开启、关闭和执行任务,那么配置大名鼎鼎的 Home Assistant 就是一个不错的选择。

第 2 节 安装

2.1 安装 Home Assistant

使用 Docker 进行安装,方法如下:

1
2
3
4
5
6
docker run -itd --name HomeAssistant --restart=always \
--privileged \
-e TZ=Asia/Shanghai \
-v /「PATH」:/config \
-p 8123:8123 \
ghcr.io/home-assistant/home-assistant:latest
信息

官网是推荐使用 Host 模式的,这种方式安装使用会比较顺利。我这里使用的桥接,感觉影响不大。

2.2 安装 HACS

HACS 全称是 Home Assistant Community Store,也就是 Home Assistant 的社区商店,安装之后安装其他插件就会轻松许多。

安装方式也很简单,首先进入 Home Assistant 的容器中:

1
docker exec -it xxxxx sh

然后执行下面这行命令:

1
wget -O - https://get.hacs.xyz | bash -

命令执行完毕,就会自动将文件下载并解压到对应位置。

2.3 启用 HACS

首先,先重启一下容器,会重新加载一遍新增的内容。

点击设置->设备与服务->添加集成->输入HACS->点击结果

https://img.papergate.top:5000/i/2025/08/689238e424fd3.webp

进行相应的配置后就启用了 HACS

第 3 节 看板配置

简单来说,我们使用 Home Assistant 所要实现的效果,就是制作一定数量的看板,并且按照一定的排版展示出来。

这些看板有一些用来展示家中各类电器的状态,一些用来控制家中各类电器的启停。比如下面这个就是一个看板,用来展示家中 Nas 设备的使用详情信息。

https://img.papergate.top:5000/i/2025/08/68923ad5c345b.webp

3.1 配置文件目录

为了讲清楚看板如何制作,先讲一下 Home Assistant 配置文件的目录详情:

我们使用 Docker 安装了 Home Assistant,并且将/config目录映射到了外部。Home Assistant 的主要配置文件都在这个/config目录下,有「三个目录」和「一个文件」比较重要:

  • custom_components:集成组件,之前安装的 HACS 就在其中,可以理解成是「后端」,用来向前端页面提供数据,执行命令。起到适配器作用,负责和电器通信,控制电器。
  • themes:主题,可以理解成是「前端样式」,配置好以后,看板的风格就确定下来了。
  • www:卡片,可以理解成是「前端结构」,配置好以后,看板的布局就确定下来了。
  • configuration.yaml:主要的配置文件。

3.2 常见组件

配置集成组件后就可以连接到对应的电器了,在 HACS 中下载:

  • Xiaomi Home:连接支持米家的设备,可以把米家中的设备导入到 Home Assistant 中。
  • Midea AC Lan:连接美的设备。
  • 天气预报:可以获取最近一段时间某个地区的天气情况。

3.3 常见卡片

在 HACS 中搜索对应卡片下载即可:

  • Mushroom:内置了很多美观的卡片,基本上是人手必备的卡片。
  • apexcharts-card:绘图卡片,将数据展示为图表。
  • mini-graph-card:另外一个绘图卡片,将数据展示为图表。
  • Tabbed Card:很方便生成 Tab 页,一块空间中可以很方便堆放多个相似的卡片。
  • Colorfulclouds Weather Card:彩云卡片,专门用来展示天气情况的,和天气预报配合使用。

3.4 主题

我用的这款主题叫做 visionOS Theme,在 HACS 中搜索对应卡片下载即可。

3.5 仪表盘

新增仪表盘

点击设置->仪表板->添加仪表板->从新建仪表盘开始

其他几个选项用到的不多,默认选择新建仪表盘就可以了。

创建视图

一个仪表盘可以创建多个视图,如下:

https://img.papergate.top:5000/i/2025/08/68924581bba31.webp

点击「箭头」可以左右移动视图的位置,点击「加号」新增视图,「铅笔」图标可以编辑视图。

编辑视图

点击「编辑视图」,如下:

https://img.papergate.top:5000/i/2025/08/689245f71e01d.webp

布局可以选择四种,部件、瀑布流、侧边栏、面板,选择前两种就可以。

  • 如果需要显示的内容比较多,需要分列显示,就选择「部件」
  • 如果需要显示的内容较少,一列就可以了,就选择「瀑布流」

其他的配置很多都可以使用默认的值,稍微修改并对比一下,很快就能理解。

新增卡片

  • 「部件」布局的时候,点击页面上的「加号」来新增卡片
  • 「瀑布流」布局的时候,点击右下角的「添加卡片」来新增卡片

大部分的卡片可以通过图形化的界面进行配置,卡片的配置过程就是将后端数据和前端模板连接到过程。配好以后,卡片中原本设定要展示数据的区域就会展示你指定的数据。

比如这个空调卡片:

https://img.papergate.top:5000/i/2025/08/68924929a3cc1.webp

在本人指定好「实体」(组件连接到电器以后,就会生成一个或者多个实体)以后,就基本配置完成了。

点击左下角的「显示代码编辑器」,可以看到如下的yaml格式的文字:

1
2
3
4
5
type: thermostat
entity: climate.xxxxx
name: 卧室空调
features:
  - type: climate-hvac-modes

有一些复杂一些的界面,只能使用yaml进行配置,不提供图形化界面。

比如之前展示的 Nas 详情信息:

https://img.papergate.top:5000/i/2025/08/68923ad5c345b.webp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
type: custom:tabbed-card
styles:
  "--mdc-theme-primary": white
  "--mdc-tab-text-label-color-default": orange
options: null
tabs:
  - card:
      type: custom:apexcharts-card
      chart_type: radialBar
      header:
        show: true
        show_states: true
        colorize_states: true
      all_series_config:
        min: 0
        max: 100
      series:
        - entity: sensor.cpu_usage
          name: CPU 使用率
        - entity: sensor.memory_percent
          name: 内存使用率
        - entity: sensor.disk_percent
          name: 硬盘使用率
    attributes:
      label: 使用详情
  - card:
      type: custom:apexcharts-card
      chart_type: donut
      header:
        show: true
        show_states: true
        colorize_states: true
      series:
        - entity: sensor.memory_used
          name: 已用内存
          unit: GB
        - entity: sensor.memory_available
          name: 可用内存
          unit: GB
    attributes:
      label: 内存详情
  - card:
      type: custom:apexcharts-card
      chart_type: donut
      header:
        show: true
        show_states: true
        colorize_states: true
      series:
        - entity: sensor.disk_used
          name: 已用存储
          unit: TB
        - entity: sensor.disk_available
          name: 可用存储
          unit: TB
    attributes:
      label: 硬盘详情

第 4 节 自定义实体

一般来说,组件连接到电器,就能够生成符合我们要求的实体。但是,如果我们想要在卡片上展示一部分我们自己获取到数据,就需要自己去编写相应的 API。

我使用的方法非常的简单,并且可以绕过 Home Assistant 自身的一些生态,非常直接的实现想要的效果。

4.1 rest 传感器

Home Assistant 提供了名为 Rest 的传感器,这种传感器的数据通过定期调用 Restful API 来获取。

configuration.yml中添加如下内容:

1
sensor: !include configuration/sensor.yaml

然后创建configuration/sensor.yaml文件,写入如下内容:

1
2
3
4
5
6
7
8
- platform: rest
  name: nas_info
  resource: "http://192.168.0.103:8000/nas_info/"
  scan_interval: 60
  json_attributes:
    - cpu
    - memory
    - disk

然后使用fastapi写一个 API 如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from fastapi import APIRouter  
import psutil  
from typing import Dict, Any  
  
router = APIRouter(prefix="/nas_info", tags=["nas_info"], responses={})  
  
@router.get("/", response_model=Dict[str, Any])  
async def nas_info():  
    cpu_info = {"percent": psutil.cpu_percent(interval=1)}  
    mem = psutil.virtual_memory()  
    memory_info = {"percent": mem.percent, "available": f"{mem.available / (1024 ** 3):.2f}",  
                   "used": f"{mem.used / (1024 ** 3):.2f}"}  
    usage = psutil.disk_usage('/')  
    disk_info = {"percent": usage.percent, "used": f"{usage.used / (1024 ** 4):.2f}",  
                 "available": f"{usage.free / (1024 ** 4):.2f}"}  
    return {"cpu": cpu_info, "memory": memory_info, "disk": disk_info}

这样,每隔60s,传感器sensor.nas_info就会调用一次 API,获取到返回的json数据。

4.2 template 模板

template 模板负责进行数据的格式转换,可以拆分复杂的数据格式,在configuration.yml中添加如下内容:

1
template: !include configuration/template.yaml

然后创建configuration/template.yaml文件,写入如下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
sensors:
  cpu_usage:
    friendly_name: "BlackHole CPU 使用率"
    unit_of_measurement: "%"
    value_template: "{{ state_attr('sensor.nas_info', 'cpu').percent}}"
  memory_percent:
    friendly_name: "BlackHole 内存使用率"
    unit_of_measurement: "%"
    value_template: "{{ state_attr('sensor.nas_info', 'memory').percent}}"
  memory_used:
    friendly_name: "BlackHole 已用内存"
    value_template: "{{ state_attr('sensor.nas_info', 'memory').used }}"
  memory_available:
    friendly_name: "BlackHole 可用内存"
    value_template: "{{ state_attr('sensor.nas_info', 'memory').available }}"

因为 Home Assistant 也是用 Python 写的,所以里头的模板语言用的是jinja

信息

Home Assistant 的大部分卡片,只支持特定数据类型的实体,比如要求实体是数值型的、要求是百分比、要求是空调、扫地机器人等电器,通常json格式的数据无法直接放到卡片中,所以要用 template 模板转换一下。

4.3 实体信息获取

有时候,我们需要获取实体的详细信息。比如,我们需要从空调实体中获取当前房间的温湿度信息。可以采用如下方式:

api/ha_entity.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from fastapi import APIRouter  
from typing import Dict, Any  
from core.homeassistant import get_entity  
  
router = APIRouter(prefix="/ha_entity", tags=["ha_entity"], responses={})  
  
  
@router.get("/{entity_id:str}", response_model=Dict[str, Any])  
async def air_conditioner_info(entity_id: str):  
    info = get_entity(entity_id)  
    return info

core/homeassistant.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import requests  
  
home_assistant_url = "http://HOST:8123"  
api_token = "xxxxx"  
  
  
# 获取实体状态  
def get_entity(entity_id):  
    url = f"{home_assistant_url}/api/states/{entity_id}"  
    headers = {"Authorization": f"Bearer {api_token}", "Content-Type": "application/json"}  
    response = requests.get(url, headers=headers)  
  
    if response.status_code == 200:  
        data = response.json()  
        return data
信息

官方有一个库,叫做homeassistant_api,可以使用pip进行安装,可以更简单实现这个效果。本人这里使用 HTTP 请求进行获取是因为本人的一个设备返回的json数据太长被截断了,使用官方的库会报错。

使用这个 API 访问一下本人的空调,得到一个类似如下的json数据:

于是就可以获取到当前房间的温度,创建一个 template 实体:

1
2
3
current_temperature:
        friendly_name: "卧室室内温度"
        value_template: "{{ state_attr('climate.xxxxx', 'current_temperature') }}"

其他设备的信息获取可以参照这个进行。

4.4 rest_command 动作

Home Assistant 有一个叫做「自动化」的功能。比如我离开家的时候,我想把空调关了,比如我快到家的时候,我想把空调打开。

自动化需要触发条件和动作两项。触发条件比较好设置,而动作通常会比较复杂,如果使用自带的图形化界面会比较繁琐,可以创建一个 rest_command 动作,触发条件以后,调用 API 执行一系列的动作。

configuration.yaml中进行如下配置:

1
rest_command: !include configuration/rest_command.yaml

然后创建configuration/rest_command.yaml文件,写入如下内容:

1
2
3
4
5
6
leave_home:
  url: "http://192.168.0.103:8000/leave/"
  method: POST
  payload: '{"place": "home"}'
  headers:
    Content-Type: "application/json"

这样,触发离家这个条件的时候,就会使用 POST 请求调用http://192.168.0.103:8000/leave/,并且传入参数{"place": "home"}

这样,只要我们写一个 API来处理后续事件即可。

信息

使用 rest_command 动作还有一个好处,就是可以在中途调用n8nmcp服务,实现更加复杂的控制效果,比如调用高德地图mcp,推算出到家的时间。