跳到主要内容

Home Assistant 智能家居中枢:打通米家、涂鸦/鹊起生态与小爱音箱毫秒级声控全实战

在全屋智能家居的实践中,“生态孤岛” 是所有极客面临的最大痛点:米家(小米)、涂鸦(Tuya / 智能生活)以及各种 OEM 贴牌厂商(如鹊起智能)各自为政,无法用单一语音助手互相调度。

本文记录在 立创·泰山派 RK3566(2G+16G)All-in-One 主机 上部署 Home Assistant Core 智能中枢,通过底层网络嗅探、AP 慢闪模式强破厂商品牌锁定、一键场景桥接以及米家云端主动推送优化,实现使用小米小爱音箱 Play 以 0.2 秒极速响应跨生态声控涂鸦工作台插座与海尔传统红外空调的完整工业级落地全流程。


1. 核心业务痛点与跨生态拓扑架构

1.1 核心攻关痛点

  1. 多品牌割裂:用户拥有小米全家桶(小爱音箱 Play、小米路由器、米家插座)、涂鸦智能插座、以及鹊起智能万能红外遥控器(控制传统海尔空调);
  2. OEM 贴牌死锁:鹊起智能设备被打上了私有 ProductKey,公版【智能生活】App 搜不到,官方扫码报 E0020003 权限拒绝;
  3. 红外万能遥控器不支持:Home Assistant 官方 Tuya 集成将万能遥控器识别为 Smart IR (unsupported)
  4. 语音轮询延迟大:传统 HA 监听小爱对话历史采用被动长轮询,存在 2~4 秒明显卡顿。

1.2 全链路端到端通信拓扑

🗣️ 用户对小爱音箱发号施令:"小爱同学,打开工作台 / 打开空调"


┌─────────────────────────────────────────────────────────────┐
│ 🔊 小米小爱音箱 Play (ASR 语义识别) │
│ └── 触发米家【打开工作台】快捷场景 (0.1s 极速 Webhook 推送)│
└──────────────────────────────┬──────────────────────────────┘
│ (主动事件推送,告别 4 秒轮询)

┌─────────────────────────────────────────────────────────────┐
│ 🥧 立创·泰山派 Home Assistant (192.168.31.32:8123) │
│ ├── [米家核心] Xiaomi Miot Auto (毫秒级捕获场景与对话事件) │
│ ├── [涂鸦中枢] Tuya Official + LocalTuya (多协议调度) │
│ └── [自动化引擎] 10ms 逻辑解析 ──> 调度目标硬件 │
└──────────────┬──────────────────────────────┬───────────────┘
│ (标准电气开关指令) │ (场景红外指令)
▼ ▼
┌──────────────────────────────┐┌─────────────────────────────┐
│ 🔌 涂鸦智能插座 (工作台) ││ 📡 鹊起万能红外遥控器 │
│ (switch.wifizhi_neng_...) ││ (192.168.31.115:6668) │
│ 瞬间通电,小爱播报反馈 ││ 发射 38kHz 海尔空调编码 │
└──────────────────────────────┘└─────────────┬───────────────┘
│ (红外光束)

┌─────────────────────────────┐
│ ❄️ 传统海尔空调 │
│ "滴" 声响起,开机制冷 26℃│
└─────────────────────────────┘

2. 泰山派 All-in-One 资源规划与容器化部署

2.1 系统资源开销实测(三合一满载)

泰山派在同时承载 Samba 局域网 NAS + AList 聚合网盘 + Home Assistant 智能中枢 的状态下,系统负载依然极低:

total used free shared buff/cache available
Mem: 1.9Gi 889Mi 206Mi 26Mi 1.1Gi 1.1Gi (可用 58%)

CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
683931f96673 homeassistant 2.48% 337.9MiB / 1.922GiB 17.17%
f465d6701f34 alist 0.00% 77.78MiB / 1.922GiB 3.95%
  • 内存占用:HA 仅消耗约 338 MB,系统可用物理内存高达 1.1 GB,Swap 消耗为 0;
  • CPU 负载:日常空闲待机 CPU < 3%,温度稳定在 39°C(无需风扇散热)。

2.2 启动 Home Assistant 核心容器

[!IMPORTANT] 智能家居容器必须采用 --net=host 网络模式,否则局域网内的 mDNS 设备发现、SSDP 广播以及小米 miio 局域网通信将被 Docker 内部网桥完全隔离。

mkdir -p /opt/all-in-one/homeassistant/config/custom_components

docker run -d \
--name homeassistant \
--restart=always \
--privileged \
--net=host \
-v /opt/all-in-one/homeassistant/config:/config \
-v /etc/localtime:/etc/localtime:ro \
-e TZ=Asia/Shanghai \
homeassistant/home-assistant:stable

3. 核心生态插件预置与加载

/opt/all-in-one/homeassistant/config/custom_components/ 目录下注入三大核心插件:

/opt/all-in-one/homeassistant/config/custom_components/
├── hacs/ # Home Assistant 官方社区商店
├── localtuya/ # 涂鸦/鹊起设备本地 AES-128 密钥直连插件
└── xiaomi_miot/ # Xiaomi Miot Auto (巴哥开发,米家全家桶核心桥梁)
  1. xiaomi_miot:通过米家云端与局域网双模连接,实现小爱音箱 Play 对话事件监听(sensor.*_conversation)、文本指令执行与自定义 TTS 播报;
  2. localtuya:针对涂鸦 Wi-Fi 设备实现本地局域网(TCP 6668/6667)直控;
  3. hacs:提供海量第三方前端卡片与集成扩展能力。

4. 破除 OEM 贴牌封锁:鹊起万能遥控器救砖与公版迁移

4.1 故障现象与根本原因

  • 现象:鹊起万能红外遥控器在公版【智能生活】App 中无法“自动搜索”发现,在 Home Assistant 中官方扫码提示 登录失败(E0020003)
  • 原因剖析:杭州鹊起科技(Larkkey Smart)作为涂鸦 OEM 贴牌厂商,在设备固件中烧录了专属 ProductKey(keyf9fsmuufeywsr),并在专属 App 中屏蔽了官方开发者 OAuth2 扫码协议,强行制造品牌壁垒。

4.2 局域网底层协议嗅探取证

在泰山派后台通过 nmap 与 UDP 嗅探捕获到的真实报文:

# 扫描局域网涂鸦标准 6668 加密端口
nmap -p 6668,6667 -sT 192.168.31.0/24 --open
  • 设备 IP192.168.31.115
  • 硬件设备 ID (DevID)28065388bcddc2fb4a90
  • 协议版本Tuya 3.3
  • 芯片:Espressif 乐鑫 ESP8266/ESP32 Wi-Fi 芯片。

4.3 终极解法:AP 热点慢闪救砖法(强行公版化)

利用涂鸦芯片底层的 AP 救砖机制,彻底绕过 OEM 品牌白名单:

  1. 进入 AP 慢闪模式
    • 长按设备配网按键 5 秒,指示灯进入快闪(EZ 模式);
    • 松开按键后,紧接着再次长按 5 秒
    • 指示灯变为 约 2~3 秒慢闪一次,代表已进入 AP 热点模式;
  2. 公版热点配网
    • 打开手机上的公版 【智能生活 (Smart Life)】 App;
    • 点击右上角【+】 $\rightarrow$ 【添加设备】 $\rightarrow$ 左侧选择【电工】 $\rightarrow$ 【万能遥控器 (Wi-Fi)】;
    • 在配网界面右上角切换为 【AP 模式 / 热点配网】
    • 手机连接遥控器发出的 SmartLife-xxxx 开放 Wi-Fi;
  3. 结果:设备被强制写入公版涂鸦云,彻底脱离鹊起 OEM 锁死,随后用【智能生活】App 扫码登录 HA 即可秒级授权成功!

5. 跨越 Smart IR (unsupported):一键场景自动桥接

5.1 痛点

官方 Tuya 集成会将红外万能遥控器和绑定的空调标记为 Smart IR (unsupported),不直接提供实体开关。

5.2 降维打击:一键执行场景同步法

在【智能生活】App 中无需编写代码,利用云端场景一键导出:

  1. 在【智能生活】App 底部点击 【场景】 $\rightarrow$ 右上角【+】 $\rightarrow$ 【一键执行】
  2. 打开空调场景
    • 任务:选择【万能遥控器】 $\rightarrow$ 【海尔空调】 $\rightarrow$ 动作设为 【电源:开 / 模式:制冷 / 温度:26℃】
    • 命名为:打开空调
  3. 关闭空调场景
    • 任务:选择【万能遥控器】 $\rightarrow$ 【海尔空调】 $\rightarrow$ 动作设为 【电源:关】
    • 命名为:关闭空调
  4. HA 自动感知
    • Home Assistant 的 Tuya 集成会自动把这两个一键执行场景映射为标准实体:
      • scene.da_kai_kong_diao
      • scene.guan_bi_kong_diao
    • 调用 scene.turn_on 即可毫秒级驱动万能遥控器发射红外光束。

6. 小爱音箱跨生态语音调度与「0.2秒极速秒开」调优

6.1 延迟根源:被动轮询 vs 主动推送

  • 被动长轮询(延迟 2~4 秒): 小爱识别后上传小米云,HA 每隔数秒主动去小米云查询对话记录,导致明显的响应卡顿;
  • 米家主动推送场景(延迟 < 0.3 秒 · 黄金解法)
    1. 在【米家 App】中新建手动执行场景,命名为 打开工作台打开空调(动作设为小爱播报“好的”或留空);
    2. 当你对小爱说出指令时,米家云端在 0.1 秒内主动向泰山派 HA 推送事件 Webhook;
    3. HA 收到推送后在 10ms 内触发涂鸦插座或万能遥控器开空调,整体延迟降至 0.2 秒,实现无感秒开

6.2 泰山派生产环境自动化源码 (automations.yaml)

泰山派 /opt/all-in-one/homeassistant/config/automations.yaml 完整生效配置:

# ==========================================
# 1. 涂鸦工作台智能插座控制
# ==========================================
- id: 'xiaoai_turn_on_workbench_socket'
alias: '小爱音箱语音联动:打开工作台插座'
description: '当小爱音箱触发 打开工作台 时,开启工作台智能插座'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{{
('打开工作台' in (trigger.to_state.state | default(''))) or
('开工作台' in (trigger.to_state.state | default(''))) or
('打开插座' in (trigger.to_state.state | default(''))) or
('打开工作台' in (trigger.event.data.query | default('')))
}}
action:
- service: switch.turn_on
target:
entity_id: switch.wifizhi_neng_cha_zuo_mc007_socket_1
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,工作台已打开"
mode: restart

- id: 'xiaoai_turn_off_workbench_socket'
alias: '小爱音箱语音联动:关闭工作台插座'
description: '当小爱音箱触发 关闭工作台 时,关闭工作台智能插座'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{{
('关闭工作台' in (trigger.to_state.state | default(''))) or
('关工作台' in (trigger.to_state.state | default(''))) or
('关闭插座' in (trigger.to_state.state | default(''))) or
('关闭工作台' in (trigger.event.data.query | default('')))
}}
action:
- service: switch.turn_off
target:
entity_id: switch.wifizhi_neng_cha_zuo_mc007_socket_1
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,工作台已关闭"
mode: restart

# ==========================================
# 2. 涂鸦万能红外遥控器 -> 海尔空调控制
# ==========================================
- id: 'xiaoai_turn_on_haier_ac'
alias: '小爱音箱语音联动:打开海尔空调'
description: '当小爱音箱触发 打开空调 时,通过涂鸦万能遥控器发射红外码'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{{
('打开空调' in (trigger.to_state.state | default(''))) or
('开空调' in (trigger.to_state.state | default(''))) or
('打开空调' in (trigger.event.data.query | default('')))
}}
action:
- service: scene.turn_on
target:
entity_id: scene.da_kai_kong_diao
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,已为你打开空调"
mode: restart

# ==========================================
# 3. 原生 Matter 卧室彩灯:动态精确数值亮度调节 (明确指定百分比)
# ==========================================
- id: 'xiaoai_exact_brightness_control'
alias: '小爱音箱语音联动:明确数值亮度调节'
description: '提取具体百分比数值(如 30%、50%、80%)精确设定 Matter 卧室灯亮度'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{% set has_digit = text | regex_findall('[0-9]+') | length > 0 %}
{% set has_chinese_pct = '百分之' in text or '亮度' in text %}
{{ ('灯' in text or '卧室' in text or '房间' in text) and (has_digit or has_chinese_pct) and ('空调' not in text) and ('工作台' not in text) and ('插座' not in text) }}
action:
- service: light.turn_on
target:
entity_id: light.wo_shi_wo_shi_deng
data:
brightness_pct: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{% set digits = text | regex_findall('[0-9]+') %}
{% if digits | length > 0 %}
{% set pct = digits[0] | int %}
{% elif '百分之十' in text or ('十' in text and '百分' in text) %}{% set pct = 10 %}
{% elif '百分之二十' in text or ('二十' in text and '百分' in text) %}{% set pct = 20 %}
{% elif '百分之三十' in text or ('三十' in text and '百分' in text) %}{% set pct = 30 %}
{% elif '百分之四十' in text or ('四十' in text and '百分' in text) %}{% set pct = 40 %}
{% elif '百分之五十' in text or ('五十' in text and '百分' in text) %}{% set pct = 50 %}
{% elif '百分之六十' in text or ('六十' in text and '百分' in text) %}{% set pct = 60 %}
{% elif '百分之七十' in text or ('七十' in text and '百分' in text) %}{% set pct = 70 %}
{% elif '百分之八十' in text or ('八十' in text and '百分' in text) %}{% set pct = 80 %}
{% elif '百分之九十' in text or ('九十' in text and '百分' in text) %}{% set pct = 90 %}
{% elif '百分之百' in text %}{% set pct = 100 %}
{% else %}{% set pct = 50 %}
{% endif %}
{{ [1, [100, pct] | min] | max }}
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{% set digits = text | regex_findall('[0-9]+') %}
{% if digits | length > 0 %}
{% set pct = digits[0] | int %}
{% elif '百分之十' in text %}{% set pct = 10 %}
{% elif '百分之二十' in text %}{% set pct = 20 %}
{% elif '百分之三十' in text %}{% set pct = 30 %}
{% elif '百分之四十' in text %}{% set pct = 40 %}
{% elif '百分之五十' in text %}{% set pct = 50 %}
{% elif '百分之六十' in text %}{% set pct = 60 %}
{% elif '百分之七十' in text %}{% set pct = 70 %}
{% elif '百分之八十' in text %}{% set pct = 80 %}
{% elif '百分之九十' in text %}{% set pct = 90 %}
{% elif '百分之百' in text %}{% set pct = 100 %}
{% else %}{% set pct = 50 %}
{% endif %}
好的,已将卧室灯亮度调至 {{ [1, [100, pct] | min] | max }}%
mode: restart

# ==========================================
# 4. 原生 Matter 卧室彩灯:基础开关与智能模糊匹配
# ==========================================
- id: 'xiaoai_turn_on_bedroom_light'
alias: '小爱音箱语音联动:打开卧室Matter灯'
description: '当小爱音箱触发任何 开灯/开卧室灯 指令时,开启卧室原生 Matter RGBCW 灯'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{% set has_digit = text | regex_findall('[0-9]+') | length > 0 %}
{{ ('灯' in text or '卧室' in text or '房间' in text) and ('开' in text) and ('关' not in text) and ('暖' not in text) and ('白' not in text) and ('色' not in text) and ('亮' not in text) and (not has_digit) and ('空调' not in text) and ('工作台' not in text) and ('插座' not in text) }}
action:
- service: light.turn_on
target:
entity_id: light.wo_shi_wo_shi_deng
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,卧室灯已打开"
mode: restart

- id: 'xiaoai_turn_off_bedroom_light'
alias: '小爱音箱语音联动:关闭卧室Matter灯'
description: '当小爱音箱触发任何 关灯/关卧室灯 指令时,关闭卧室原生 Matter RGBCW 灯'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{{ ('灯' in text or '卧室' in text or '房间' in text) and ('关' in text) and ('空调' not in text) and ('工作台' not in text) and ('插座' not in text) }}
action:
- service: light.turn_off
target:
entity_id: light.wo_shi_wo_shi_deng
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,卧室灯已关闭"
mode: restart

# ==========================================
# 5. 原生 Matter 卧室彩灯:色温调节 (暖光/冷光/白光)
# ==========================================
- id: 'xiaoai_color_temp_warm_light'
alias: '小爱音箱语音联动:卧室灯调成暖光'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{{ ('灯' in text or '卧室' in text) and ('暖光' in text or '暖色' in text or '黄光' in text or '温馨' in text) }}
action:
- service: light.turn_on
target:
entity_id: light.wo_shi_wo_shi_deng
data:
color_temp_kelvin: 2700
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,已为你调成暖光"
mode: restart

- id: 'xiaoai_color_temp_white_light'
alias: '小爱音箱语音联动:卧室灯调成冷白光'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{{ ('灯' in text or '卧室' in text) and ('白光' in text or '冷光' in text or '日光' in text or '正常光' in text) }}
action:
- service: light.turn_on
target:
entity_id: light.wo_shi_wo_shi_deng
data:
color_temp_kelvin: 5000
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,已为你调成冷白光"
mode: restart

# ==========================================
# 6. 原生 Matter 卧室彩灯:1600万色调色 (红/绿/蓝/粉/紫/黄/橙)
# ==========================================
- id: 'xiaoai_rgb_color_control'
alias: '小爱音箱语音联动:卧室灯RGB变色'
trigger:
- platform: state
entity_id: sensor.xiaomi_l05b_b558_conversation
- platform: event
event_type: xiaomi_miot.xiaoai_conversation
condition:
- condition: template
value_template: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{{ ('灯' in text or '卧室' in text) and ('红' in text or '绿' in text or '蓝' in text or '粉' in text or '紫' in text or '黄' in text or '青' in text or '橙' in text) and ('空调' not in text) }}
action:
- service: light.turn_on
target:
entity_id: light.wo_shi_wo_shi_deng
data:
rgb_color: >-
{% set text = trigger.to_state.state if trigger.platform == 'state' else (trigger.event.data.query if trigger.event is defined and trigger.event.data is defined else '') %}
{% if '红' in text %}[255, 0, 0]
{% elif '绿' in text %}[0, 255, 0]
{% elif '蓝' in text %}[0, 100, 255]
{% elif '粉' in text %}[255, 105, 180]
{% elif '紫' in text %}[128, 0, 128]
{% elif '黄' in text %}[255, 255, 0]
{% elif '橙' in text %}[255, 140, 0]
{% else %}[255, 255, 255]
{% endif %}
- service: text.set_value
target:
entity_id: text.xiaomi_l05b_b558_play_text
data:
value: "好的,已为你变换灯光色彩"
mode: restart

7. 生产环境速查与排障手册

7.1 核心服务访问入口

  • Home Assistant 控制台:👉 http://nas.local:8123(或 http://192.168.31.32:8123
  • AList 聚合网盘:👉 http://nas.local(端口 80 / 5244)
  • Samba 共享:👉 \\nas.local\NAS(Windows Y: 盘)

7.2 常用运维管理命令

# 查看 Home Assistant 运行日志
docker logs -f homeassistant --tail 50

# 热重启 Home Assistant 容器
docker restart homeassistant

# 查看泰山派整体资源负载与容器占用
docker stats --no-stream

7.3 常见问题排查(FAQ)

  1. Q:小爱偶尔多嘴说“未找到设备”怎么办?
    • A:直接对小爱说:“小爱同学,我要训练你。我说打开工作台你回答好的”,或者在米家 App 的【小爱训练】中将该口令的回复设为静默。
  2. Q:如果家里外网断网,智能家居还能控制吗?
    • A:电脑/手机登录 http://nas.local:8123,在局域网内直接点击开关依然 100% 能够控制涂鸦与米家局域网设备。