【插件】智能音箱接入Home Assistant整合

前情回顾:年前折腾的通用智能音箱接入平台因音箱技能类型限制不过审翻车了,然后将项目成果整理做了个智能音箱mqtt代理转发插件。考虑到易用性,趁着过年闲着,于是折腾了下各个平台的智能家居类型技能对接,最终成果就是这么一个整合版插件了。


1.插件说明

本插件实际上由两大功能模块组成:

  • MQTT对接服务

    配合本人搭建的mqtt中转服务,可以将音箱云平台的音箱命令消息、oauth消息转发到无公网环境下家中的Home Assistant。

  • 音箱组件

    即智能音箱本地网关插件,对音箱云平台的音箱命令消息进行解析、处理,可以初始化为HTTP网关服务与音箱云平台直接对接。

有三种使用模式,适合不同场景的接入:

  • 模式一 http模式

    • 生成音箱http网关,通过自建测试技能接入
    • 适合家庭宽带有公网ip或已实现内网穿透场景下使用
    • 建议有条件都用这个,留服务资源给有需要的人
  • 模式二 http proxy模式

    • 生成音箱http网关,同时使用mqtt代理穿透内网访问,通过自建测试技能接入
    • 适合家庭宽带无公网ip场景下使用
    • 临时提供,视服务资源情况会停止
  • 模式三 skill模式

    • 通过官方音箱APP技能接入,目前技能已暂未上线 (也许没法上线)
    • 适合无公网省事场景使用
    • 服务资源有限不能保证稳定
  • 各模式难度指数

    模式一:★★★★☆

    模式二:★★☆☆☆

    模式三:★☆☆☆☆

INFO:不同模式的配置方法见3.3HA插件配置章节。

智能音箱组件说明

  • 天猫精灵插件基于瀚思彼岸论坛@feversky的插件小修改
  • 小度音箱插件基于瀚思彼岸论坛@zhkufish的插件小修改
  • 叮咚音箱插件参考前两个插件编写

aihome线上服务劝退警告

  • aihome线上服务(指模式二、三的mqtt中转服务及APP技能)可以实现叮咚音箱、天猫精灵、小度音箱接入Home Assistant(免公网IP),语音控制家中设备。线上服务主要目的在于测试、学习、交流,受限于个人能力,无法保证提供完善服务,并且使用线上服务有一定的风险,介意者建议另行部署自用的环境对接智能音箱平台。
  • 隐私安全
    • 为解决无公网IP的家庭宽带环境下使用的痛点,线上服务采用mqtt中转的技术方案,该方案下控制消息需经个人服务器转发,存在被本人监控、冒充控制消息的风险。
    • mqtt中转模式下已采用了消息隔离、消息加密、设备entity_id加密等方式对用户的控制消息进行安全保障,但仍可能存在本人没考虑全面的安全风险。
  • 服务质量
    • 只能尽个人最大能力保证,毕竟存在不可抗力自然因素、断电、断网、服务器宕机、本人偷懒等诸多不可控风险。
    • 如果不幸本人跑路,因为相关设备信息(设备个性化配置)只保留在本地,你仍可以自行部署自用环境对接智能音箱平台继续使用。
  • 服务支持
    • 本服务实质上只提供便捷接入途径,后续仍要对设备信息进行个性化配置,需要对各家音箱平台的控制指令有一定了解。
    • 使用本服务上手有一定难度,建议心平气和慢慢熟悉,遇到问题可加QQ群寻求帮助。
    • 因个人时间有限,只侧重支撑解决使用mqtt中转服务和使用插件遇到的问题;部署自用环境对接方面问题请自行查阅厂家技能开放平台文档。

2.完成度

控制指令

  • 灯、开关类型设备的开/关
  • 电源状态、温度、湿度等状态查询

INFO:能用的控制指令实际上与各智能音箱组件对音箱平台预设功能指令的支持度有关,因各个音箱平台有差异,无法一一描述,只能先列举叮咚音箱组件下目前个人已测试的功能。

支持平台

  • 天猫精灵:已自建技能测试;技能已上线,音箱APP搜“aihome智能”
  • 小度:已自建技能测试;技能已上线,音箱APP搜“aihome”
  • 叮咚:已自建技能测试;技能已上线,音箱APP搜“aihome”
  • echo:计划中
  • 小爱:计划外
  • 有其它音箱接入需求可以反馈我研究下

高能提醒

  • 设备配置各个音箱平台会有一些出入,需要一定耐心熟悉上手
  • 多用户使用场景没有条件测试,估计有不少bug
  • 多用户并发下服务器处理性能及带宽可能有瓶颈问题

3.使用说明

3.0准备

  • 下载插件:aihome
  • 确认采取哪种模式接入

3.1获取账号

注:模式一跳过此步骤

打开账号获取页面,获取AppKey和AppSecret

INFO:模式三需要注册用户登陆;模式二可以不登陆(暂时)。

3.2音箱技能平台配置

注:模式三跳过此步骤
启用模式一或模式二,会生成服务网关(不分音箱平台),访问uri为/aihome_service

  • 模式一

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #前往厂家的音箱技能平台进行设置

    #授权地址
    https://{你的域名}/auth/authorize
    #Client_Id,回调地址域名那一串即可
    小度:https://xiaodu.baidu.com
    天猫:https://open.bot.tmall.com
    #Token地址
    https://{你的域名}/aihome_auth
    #WebService地址(服务网关)
    https://{你的域名}/aihome_service

    INFO:需要自己解决域名访问问题,建议观看天猫精灵、小度音箱原版插件的教程。

  • 模式二

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #前往厂家的音箱技能平台进行设置
    #模式一填自己设置的web服务url,可参考天猫精灵、小度音箱原版插件的教程。
    #授权地址
    https://{本地HA访问地址}/auth/authorize
    #Client_Id,回调地址域名那一串即可
    小度:https://xiaodu.baidu.com
    天猫:https://open.bot.tmall.com
    #Token地址
    https://ai-home.ljr.im/h2m2h/{app_key}/aihome_auth
    #WebService地址(服务网关)
    https://ai-home.ljr.im/h2m2h/{app_key}/aihome_service

    INFO:{本地HA访问地址}、{app_key}替换成相应的字符串。
    INFO:目前叮咚技能需要联系工作人员审核后才能绑定到指定音箱,另外client_id格式不能填写”https://“,与HA的oauth格式要求不符,需要修改HA对应组件的代码。

3.3HA插件配置

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
#{HA配置目录}/configuration.yaml                 
aihome:
# 启用音箱平台,至少启用一个
platform:
- aligenie # 天猫精灵
- dueros # 小度
- jdwhale # 叮咚
# 启用模式一
http:
# ha_url: https://localhost:8123 # HA所在主机/容器IP地址,不设置则默认识别
# expire_in_hours: 24 # token超时时间,单位小时,不设置则默认24h
# 启用模式二(注意,必需同时启用模式一)
http_proxy:
# ha_url: https://localhost:8123 # HA所在主机/容器IP地址,不设置则默认识别
# allowed_uri: # http请求白名单,不设置则默认['/aihome_auth', '/aihome_service']
# - /aihome_auth
# - /aihome_service
# 启用模式三
skill:
# sync: False # 不主动上报设备状态,不设置则默认不上报(小度音箱才有效)
# mqtt相关设置,仅启用模式二或模式三才有效
setting:
app_key: {{your_app_key}} # 必填,https://ai-home.ljr.im/account/获取
app_secret: {{your_app_secret}} # 必填,https://ai-home.ljr.im/account/获取
entity_key: {{your_entity_key}} # 必填,加密entity_id的key,自定义16个字符

3.4HA设备个性化配置

音箱云平台的设备与HA的设备属性字段有出入,HA中需要使用个性化配置文件(customize.yaml)补充额外的属性,使得音箱云平台可以识别设备。虽然音箱插件会尝试根据设备类型、设备名称进行自动补充,但目前准确率仍不高,建议还是尽量手动指定。

3.4.1 整体配置框架

以接入一个灯类设备、传感器类设备为例,会涉及几个大块配置。

  • 方法1 分散文件配置方式

    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
    #{HA配置目录}/customize.yaml,>设备个性化配置<
    light.demo: # 接入音箱平台的灯(一般设备配置属性即可)
    属性1:
    属性2:
    sensor.livingroom: # 接入音箱平台的传感器(虚拟创建的)
    属性1:
    属性2:
    sensor.temperature: # 虚拟传感器关联的真实传感器设备(作为一种参数查询,如温度)
    属性1:
    sensor.humidity: # 虚拟传感器关联的真实传感器设备(作为一种参数查询,如湿度)
    属性1:
    #{HA配置目录}/configuration.yaml,虚拟传感器
    sensor:
    - platform: template
    sensors:
    livingroom: # 新增虚拟传感器设备,该设备在音箱云平台展示
    value_template: "客厅环境"

    #{HA配置目录}/group.yaml,虚拟传感器关联的传感器类分组
    livingroom_sensors:
    view: no
    name: '客厅传感器列表'
    control: hidden
    entities: # 真实传感器列表,真实传感器配置过程省略
    - sensor.temperature
    - sensor.humidity
  • 方法2 统一文件配置方式(建议)

    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
    #编辑{HA配置目录}/configuration.yaml,引入packages目录
    homeassistant:
    packages: !include_dir_named packages

    #编辑{HA配置目录}/packages/自定义名称.yaml, 增加设备个性化配置、新增虚拟传感器、传感器分组等信息
    homeassistant:
    customize: # >设备个性化配置<
    light.demo: # 接入音箱平台的灯(一般设备配置属性即可)
    属性1:
    属性2:
    sensor.livingroom: # 接入音箱平台的传感器(虚拟创建的)
    属性1:
    属性2:
    sensor.temperature: # 虚拟传感器关联的真实传感器设备(作为一种参数查询,如温度)
    属性1:
    sensor.humidity: # 虚拟传感器关联的真实传感器设备(作为一种参数查询,如湿度)
    属性1:
    group: # 虚拟传感器关联的传感器类分组
    livingroom_sensors:
    view: no
    name: '客厅传感器列表'
    control: hidden
    entities: # 真实传感器列表,真实传感器配置过程省略
    - sensor.temperature
    - sensor.humidity
    sensor: # 虚拟传感器
    - platform: template
    sensors:
    livingroom: # 新增虚拟传感器设备,该设备在音箱云平台展示
    value_template: "客厅环境"

3.4.2 设备个性化配置属性

使用官方自带的customize组件({HA配置目录}/customize.yaml中配置)为HA的设备增加相关属性,音箱插件根据属性信息生成音箱平台可识别的设备。在3.4.1章节>设备个性化配置<部分,可以为指定的HA设备(entity_id)增加相关的属性。

  • 通用

    1
    2
    # 指定的设备可被发现,上报设备数据
    aihome_device: True
  • 传感器专用

    1
    2
    3
    4
    # 虚拟传感器,关联真实传感器分组,详细用法见传感器类设备配置说明
    aihome_sensor_group: group.livingroom_sensors
    # 真实传感器标识,详细用法见传感器类设备配置说明
    aihome_sensor: True
  • 叮咚音箱

    1
    2
    3
    4
    # 设备类型,不设置则尝试自动生成
    jdwhale_deviceType: 'LIGHT'
    # 设备支持操作,不设置则尝试自动生成
    jdwhale_actions: ['TurnOn', 'TurnOff', 'Query']
  • 天猫精灵

    1
    2
    3
    4
    5
    6
    7
    8
    # 设备别名(设备类型限定设备别名可取值)
    aligenie_deviceName:
    # 设备位置,不设置则尝试自动生成
    aligenie_zone: 主卧
    # 设备类型,不设置则尝试自动生成
    aligenie_deviceType: 'light'
    # 设备支持操作,不设置则尝试自动生成
    aligenie_actions: ["TurnOn", "TurnOff"]
  • 小度音箱

    1
    2
    3
    4
    # 设备类型,不设置则尝试自动生成
    dueros_deviceType: 'LIGHT'
    # 设备支持操作,不设置则尝试自动生成
    dueros_actions: ['turnOn', 'turnOff']

INFO:音箱的设备类型、支持的操作建议去官网看相应智能家居技能文档,无法一一详述。

3.4.3 特殊设备配置说明

  • 传感器类设备配置

    HA中,一个传感器设备只有一种数据,而音箱云平台可以对设备查询多种属性,因此需要虚拟一个新的传感器设备整合多个真实传感器数据。

    1. 环境类传感器先集中到一个分组

      1
      2
      3
      4
      5
      6
      7
      8
      #{HA配置目录}/group.yaml,虚拟传感器关联的传感器类分组
      livingroom_sensors:
      view: no
      name: '客厅传感器列表'
      control: hidden
      entities: # 真实传感器列表
      - sensor.temperature
      - sensor.humidity
    2. 新增一个虚拟的sensor(使用官方sensor组件template生成即可)

      1
      2
      3
      4
      5
      6
      #{HA配置目录}/configuration.yaml,虚拟传感器
      sensor:
      - platform: template
      sensors:
      livingroom: # 新增虚拟传感器设备,该设备在音箱云平台展示
      value_template: "客厅环境"
    3. 自定义虚拟sensor的属性,关联传感器分组

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      #{HA配置目录}/customize.yaml,设备个性化配置

      sensor.livingroom:
      aihome_device: True # 上报设备
      friendly_name: 客厅传感器
      aihome_sensor_group: group.livingroom_sensors # 关联真实传感器分组
      jdwhale_actions: ['Query', 'QueryTemperature', 'QueryHumidity'] # 叮咚平台设置,需根据真实传感器及音箱平台支持的类型设置

      # 真实传感器设置aihome_sensor属性
      sensor.temperature:
      aihome_sensor: True
      sensor.humidity:
      aihome_sensor: True

    INFO:建议虚拟sensor的名称命名为“{房间名}传感器”,各个平台的识别执行成功率比较高。

INFO:原天猫精灵插件根据zone组合传感器,原小度插件没有实现相应查询功能,于是对查询方法进行了统一。

  • 直接调service类设备配置说明

    可以手动指定调用服务命令,效果和新建简单脚本再调用类似。

    1. 新增一个input_boolean

      1
      2
      3
      #{HA配置目录}/configuration.yaml
      input_boolean:
      call_service:
    2. 自定义虚拟input_boolean的属性,在aihome_actions属性中设置对应的service指令(只能设置turn_on/turn_off/increase_brightness/decrease_brightness,对应打开/关闭/调高亮度/调低亮度指令)

      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
      #{HA配置目录}/customize.yaml
      input_boolean.call_service:
      friendly_name: 定时充电
      #↓↓↓该部分根据使用的音箱精简↓↓↓
      aihome_device: True
      aligenie_deviceName: 开关
      aligenie_zone: 主卧
      aligenie_deviceType: switch
      # aligenie_actions: ["TurnOn", "TurnOff"] # 新版本已可根据aihome_actions自动识别
      dueros_deviceType: 'SWITCH'
      # dueros_actions: ['turnOn', 'turnOff'] # 新版本已可根据aihome_actions自动识别
      jdwhale_deviceType: 'SWITCH'
      # jdwhale_actions: ['TurnOn', 'TurnOff'] # 新版本已可根据aihome_actions自动识别
      #↑↑↑该部分根据使用的音箱精简↑↑↑
      #↓↓↓指令根据实际需要配置↓↓↓
      aihome_actions:
      # service指令格式:[domain, service_name, service_data(json字符串)],具体内容需参见相应组件的服务定义。
      # 注意,参数变更为数组以支持多条指令,单条指令也别忘了加-
      turn_on:
      - ['common_timer', 'set', '{"entity_id":"switch.demo","duration":"01:00:00","operation":"off"}'] # 打开命令
      - ['input_boolean', 'turn_on', '{}'] # 同步打开状态
      turn_off:
      - ['common_timer', 'cancel', '{"entity_id":"switch.demo"}'] # 关闭命令
      - ['input_boolean', 'turn_off', '{}'] # 同步关闭状态
      increase_brightness:
      - ['指令1']
      - ['指令2']
      decrease_brightness:
      - ['指令1']
      - ['指令2']

    INFO:调自动化(automation.turn_on)、调脚本(scrpit.turn_on)、调红外指令(climate.xiaomi_miio_send_command)等会比较适合。

    INFO:天猫精灵无法自定义名称,不太适合使用。

3.4.4 配置样例

采用统一文件配置方式,引入packages目录及即可测试,引入方法见3.4.1。

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
58
59
60
61
62
63
64
65
66
67
68
69
70
#{HA配置目录}/packages/aihome_template.yaml
homeassistant: # 用于生成音箱平台设备
customize:
# 一般设备,switch light fan input_boolean cover等
input_boolean.aihome_demo_light: # 平台已有设备的entity_id。开关类的是switch.xxx,灯类的是light.xxx,HA左侧开发者工具第二个图标可以查看当前HA所有的entities。
friendly_name: 厨房灯 # 设备别名,小度音箱和叮咚音箱使用这个名称进行控制
aihome_device: True # 该设备可被发现
# 天猫精灵专用 <测试指令:打开/关闭厨房灯>
aligenie_deviceName: # 设备品类别名,https://open.bot.tmall.com/oauth/api/aliaslist
aligenie_zone: 厨房 # 房间名,https://open.bot.tmall.com/oauth/api/placelist
aligenie_deviceType: light # 设备品类,https://doc-bot.tmall.com/docs/doc.htm?treeId=393&articleId=108271&docType=1
aligenie_actions: ["TurnOn", "TurnOff"] # 指定设备支持的操作,https://doc-bot.tmall.com/docs/doc.htm?spm=0.7629140.0.0.2b131780Fl14V8&treeId=393&articleId=108264&docType=1
# 小度音箱专用 <测试指令:打开/关闭厨房灯>
dueros_deviceType: 'LIGHT' # 指定设备类型,https://dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-smart-home/protocol/discovery-message_markdown
dueros_actions: ['turnOn', 'turnOff'] # 指定设备支持操作,https://dueros.baidu.com/didp/doc/dueros-bot-platform/dbp-smart-home/protocol/control-message_markdown
# 叮咚音箱专用 <测试指令:打开/关闭厨房灯>
jdwhale_deviceType: 'SWITCH' # 指定设备类型,http://jdwhale.jd.com/Docs/skillManager#shebeifaxianfanhui
jdwhale_actions: ['TurnOn', 'TurnOff', 'Query', 'QueryPowerState'] # 指定设备支持操作,http://jdwhale.jd.com/Docs/skillManager#dakaishebei

# 环境类传感器,虚拟的sensor
sensor.aihome_demo_sensor:
friendly_name: 客厅传感器
aihome_device: True
aihome_sensor_group: group.aihome_demo_sensors # 关联一个传感器分组,从分组的真实传感器取数据
# 天猫精灵专用 <测试指令:查询客厅传感器的温度/湿度>
aligenie_deviceName: 传感器
aligenie_zone: 客厅
aligenie_deviceType: sensor # 可自动识别,可省略
aligenie_actions: ['Query', 'QueryTemperature', 'QueryHumidity'] # 只测试查询温度、湿度
# 小度音箱专用 <测试指令:查询客厅传感器的温度/湿度>
dueros_deviceType: AIR_MONITOR # 无传感器类别,默认为空气监测器类设备,可省略
dueros_actions: ["getTemperatureReading", "getHumidity"] # 只测试查询温度、湿度
# 叮咚音箱专用 <测试指令:查询客厅传感器的温度/湿度>
jdwhale_deviceType: AIR_CLEANER # 无传感器类别,默认为空气净化器类设备,可省略
jdwhale_actions: ['Query', 'QueryTemperature', 'QueryHumidity'] # 只测试查询温度、湿度
# 真实传感器
sensor.aihome_demo_temperature:
aihome_sensor: True # 上报传感器数据
# 真实传感器
sensor.aihome_demo_humidity:
aihome_sensor: True # 上报传感器数据

group:
# 新增,传感器分组
aihome_demo_sensors:
view: no
name: '客厅传感器列表'
control: hidden
entities: # 关联真实传感器列表
- sensor.aihome_demo_temperature
- sensor.aihome_demo_humidity

sensor:
- platform: template
sensors:
# 演示用
aihome_demo_temperature:
unit_of_measurement: '°C'
value_template: "20"
# 演示用
aihome_demo_humidity:
unit_of_measurement: '%'
value_template: "60"
# 新增,虚拟的sensor
aihome_demo_sensor:
value_template: "虚拟的传感器"

input_boolean:
# 演示用
aihome_demo_light:

3.5控制指令说明

  • 叮咚

    • 打开/关闭

      1
      2
      3
      4
      #打开/关闭
      #用途:一般为电源控制
      #语义:打开/关闭{设备名称}
      #例子:打开主卧灯
    • 查询状态

      1
      2
      3
      4
      #打开/关闭
      #用途:查询设备状态
      #语义:查询{设备名称}的{状态/xx状态}
      #例子:查询主卧传感器的状态;查询主卧传感器的温度;查询主卧灯的电源状态

    INFO:传感器信息需要挂靠到具体设备上进行查询。一般来说温度、湿度需要挂靠到空气净化器类型上。

  • 天猫精灵

    • 打开/关闭
      1
      2
      3
      4
      5
      #打开/关闭
      #用途:一般为电源控制
      #语义:打开/关闭{房间名}的{设备类型/别名}
      #例子:打开主卧的灯。
      #备注:{房间名}、{设备类型/别名}需要指定,均为枚举值

    INFO:优先匹配“位置(可为空)+别名”:例如有台灯、灯两个设备,“打开台灯”则精确匹配台灯;然后匹配“位置(可为空)+设备类型”,例如有一个台灯设备,“打开吸顶灯”、“打开床头灯”等都可控制。指令不带位置,如设备别名多个匹配,询问设备位置;当有相同匹配,一起执行。

    • 查询状态
      1
      2
      3
      4
      #打开/关闭
      #用途:查询设备状态
      #语义:查询{房间名}{设备类型/别名}的{状态/xx状态}
      #例子:查询主卧传感器的状态;查询主卧传感器的温度

    INFO:查询传感器好像有个bug:查询所有状态不能正常播报;查询单个状态,发送的指令是查询所有状态的指令。

  • 小度

    • 打开/关闭
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      #打开/关闭
      #用途:一般为电源控制
      #语义:打开/关闭{设备名称}
      #例子:打开主卧灯
      ```
      - 查询状态
      ```yaml
      #打开/关闭
      #用途:查询设备状态
      #语义:查询{设备名称}的{xx状态}
      #例子:查询主卧传感器的温度

    INFO:只能查询单一状态。


4.小结

  • 重新对各音箱平台智能家居指令进行分析,目前智能音箱插件功能实现度还有比较大的改进空间,但不同音箱如何统一整合还要好好考虑。
  • 对原有多用户场景下mqtt消息发送、处理方式进行了重构。