『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 1571|回复: 13

[经验分享] (全资料)中控屏语音助手

[复制链接]

15

主题

186

帖子

1023

积分

金牌会员

Rank: 6Rank: 6

积分
1023
金钱
837
HASS币
0
发表于 2024-6-29 00:12:24 | 显示全部楼层 |阅读模式
本帖最后由 duanyudan123 于 2024-10-11 15:23 编辑

1、启明智显的4吋触摸屏(没有供电板)+openhasp来做的UI2、ac-dc电路自己画的板,附加语音功能。供电加语音一体。
3、使用esphome的语音助手组件
4、唤醒词使用的snowboy(本地)
5、语音转文字使用faster-whisper(本地cuda环境工作的)
6、文字转语音(云端的edgetts),piper本地部署讲中文好似洋人说的蹩脚中文,洋鬼子口音。edge比较省事不二选择
7、ha的对话代理+豆包的对话代理

以下演示的视频前半部分是ha自带的对话代理,后半部分是豆包模型的对话代理。没有配置意图的情况下都不尽如人意。
[media=x,500,375] https://b23.tv/SSdYzou[/media]

整个项目还是很繁琐的,而且还有很多地方都需要优化。如果论坛小伙伴有需要我将把所有资料放上来。
成本呢屏幕加语音板150-220左右。还有一个就是语音识别这个看自己想办法了。我是装了一个5000的电脑,实在不建议,反正有给gpu和没gpu是两回事,自己决断。有很多平替方案。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2024/10/11[media=x,500,375]【演示视频】 https://www.bilibili.com/video/B ... 39248b018c90a8495aa[/media]
1、1个触摸屏硬件:启明智显ZX3D95CE01S-R
2、1个喇叭:喇叭2030
3、1个天线:fpc天线
4、1个音频功放:MAX98357 I2S 音频放大器模块拆焊取器件节省成本
5、1个麦克风:INMP441全向麦克风模块拆焊取器件节省成本
6、1个AC-DC:AC-DC稳压/220转5V
7、1个ESP32-S3-N16R8
8、1个ASR-PRO-2M:ASR PRO语音识别模块顺带捎上2块得麦克风
9、1个86底盒:86中控屏幕智能开关底座
10、语音+电源+ASR-PRO缝合板(对插和缝合ASR-PRO未完成希望有人补充优化实在画不动了): esp32语音版 AC-DC.zip (586.64 KB, 下载次数: 0)
11、马蹄接线柱(我是从其它开关拆的这个需要自己适配)
12、连接线若干(如果有人优化对插则不需要)
以上是全部硬件需要自己焊接打板(最好能有人优化一下板子传上来)---------------------------------------------------------------------------------------------------------------------------------
软件部分:
openhasp:openHASP选择PanleeZW3D95CE01S-TR
界面UI:
{"page":1,"id":1,"obj":"img","x": 160,"y": 10,"w": 320,"h": 320,"bg_opa":255,"src":"L:/bj1.png"}
{"page":1,"comment":"------------------主页标签"}
{"page": 1,"id": 10,"obj": "label","x": 5,"y": 10,"w": 150,"h": 150,"bg_opa":255,"text":"\n\n\n\n主页","text_font":"hmf25","align":"center","bg_color":"#6CEBED","radius":5,"value_str":"\uE2DC","value_font":"60","value_align":"0","value_color":"#FFFD55","action": {"down": "p1b60.val=0"}}
{"page":1,"comment":"------------------温控标签"}
{"page": 1,"id": 20,"obj": "label","x": 5,"y": 165,"w": 150,"h": 150,"bg_opa":255,"text":"\n\n\n\n温控","text_font":"hmf25","align":"center","bg_color":"#77FF63","radius":5,"value_str":"\uE01B","value_font":"60","value_align":"0","value_color":"#FFFD55","action": {"down": "p1b60.val=1"}}
{"page": 1,"id": 21,"obj": "btn","x": 95,"y":5,"w": 50,"h": 50,"bg_opa":70,"parentid":20,"radius":30,"text":"\uE425","text_font":40,"align":"center","bg_grad_dir":0,"border_side":0,"bg_color":"#418C36","text_color":"#969696"}
{"page":1,"comment":"------------------灯光标签1"}
{"page": 1,"id": 30,"obj": "label","x": 5,"y":320,"w": 150,"h": 150,"bg_opa":255,"text":"\n\n\n\n灯光1","text_font":"hmf25","align":"center","bg_color":"#409BE3","radius":5,"value_str":"\uE6E8","value_font":"60","value_align":"0","value_color":"#FFFD55"}
{"page": 1,"id": 31,"obj": "btn","x": 95,"y":5,"w": 50,"h": 50,"bg_opa":70,"parentid":30,"radius":30,"text":"\uE1D9","text_font":40,"align":"center","bg_grad_dir":0,"border_side":0,"bg_color":"#418C36","text_color":"#FFFFFF","action": {"down": "p1b60.val=2"}}
{"page":1,"comment":"------------------灯光标签2"}
{"page": 1,"id": 40,"obj": "label","x": 160,"y": 320,"w": 155,"h": 150,"bg_opa":255,"text":"\n\n\n\n灯光2","text_font":"hmf25","align":"center","bg_color":"#E6817E","radius":5,"value_str":"\uE6E8","value_font":"60","value_align":"0","value_color":"#FFFD55"}
{"page": 1,"id": 41,"obj": "btn","x": 95,"y":5,"w": 50,"h": 50,"bg_opa":70,"parentid":40,"radius":30,"text":"\uE1D9","text_font":40,"align":"center","bg_grad_dir":0,"border_side":0,"bg_color":"#418C36","text_color":"#FFFFFF","action": {"down": "p1b60.val=3"}}
{"page":1,"comment":"------------------灯光标签3"}
{"page": 1,"id": 50,"obj": "label","x": 320,"y": 320,"w": 155,"h": 150,"bg_opa":255,"text":"\n\n\n\n灯光3","text_font":"hmf25","align":"center","bg_color":"#8A1E94","radius":5,"value_str":"\uE6E8","value_font":"60","value_align":"0","value_color":"#FFFD55"}
{"page": 1,"id": 51,"obj": "btn","x": 95,"y":5,"w": 50,"h": 50,"bg_opa":70,"parentid":50,"radius":30,"text":"\uE1D9","text_font":40,"align":"center","bg_grad_dir":0,"border_side":0,"bg_color":"#418C36","text_color":"#FFFFFF","action": {"down": "p1b60.val=4"}}
{"page":1,"comment":"------------------选项卡主体"}
{"page":1,"id":60,"obj":"tabview","btn_pos":0,"x":160,"y":10,"w":325,"h":315,"bg_opa":0,"border_opa":0,"bg_color":"#E6817E","bg_grad_dir":0,"hidden":0}
{"page":1,"id":70,"obj":"tab","parentid":60,"text":"Tab 0"}
{"page":1,"id":80,"obj":"tab","parentid":60,"text":"Tab 1"}
{"page":1,"id":90,"obj":"tab","parentid":60,"text":"Tab 2"}
{"page":1,"id":100,"obj":"tab","parentid":60,"text":"Tab 3"}
{"page":1,"id":110,"obj":"tab","parentid":60,"text":"Tab 4"}
{"page":1,"comment":"------------------选项卡主页"}
{"page":1,"id":120,"obj":"label","x":0,"y":0,"w":315,"h":150,"parentid":70,"bg_opa":0,"template":"%H:%M","text_font":120,"align":"center","hidden":0}
{"page":1,"id":130,"obj":"label","x":0,"y":155,"w":150,"h":150,"parentid":70,"bg_opa":0,"text":"\uE596","text_font":120,"align":"center","hidden":0}
{"page":1,"id":140,"obj":"label","x":155,"y":155,"w":160,"h":80,"parentid":70,"bg_opa":0,"text":"20.9°C","text_font":60,"align":"center","hidden":0}
{"page":1,"id":150,"obj":"label","x":155,"y":235,"w":160,"h":70,"parentid":70,"bg_opa":0,"text":"多云 30/24°C\n10月19日星期四\n八月十七","text_font":"hmf20","align":"center","hidden":0}
{"page":1,"comment":"------------------选项卡温控页"}
{"page":1,"id":160,"obj":"gauge","x":65,"y":25,"w":200,"h":200,"parentid":80,"min":170,"max":300,"val":0,"format":1,"critical_value":301,"label_count":14,"line_count":27,"border_width":0,"pad_top":2,"pad_bottom":2,"pad_left":2,"pad_right":2,"value_str":"°C","value_ofs_y":55,"value_font":30,"bg_opa":0,"line_width10":5,"line_rounded10":1,"line_color":"#348feb","line_color60":"#348feb","scale_grad_color":"#eb4934","scale_grad_color60":"#eb4934","scale_end_color60":"#eb4934","pad_inner":16,"text_font":20,"hidden":0}
{"page":1,"id":170,"obj":"arc","x":40,"y":0,"w":250,"h":250,"parentid":80,"min":17,"max":30,"val":26,"border_side":0,"type":0,"rotation":0,"start_angle":135,"end_angle":45,"adjustable":"true","line_width":21,"line_width10":21,"line_color10":"#34bdeb","bg_opa":0,"pad_top20":5,"pad_bottom20":5,"pad_left20":5,"pad_right20":5,"pad_top":5,"pad_bottom":5,"pad_left":5,"pad_right":5,"hidden":0}
{"page":1,"id":180,"obj":"btn","x":0,"y":235,"w":70,"h":70,"radius":5,"parentid":80,"bg_opa":255,"bg_grad_dir":0,"bg_color":"#52AFFA","bg_color02":"#C2BC29","border_side":0,"text":"\uE717","text_font":50}
{"page":1,"id":190,"obj":"btn","x":82,"y":235,"w":70,"h":70,"radius":5,"parentid":80,"bg_opa":255,"bg_grad_dir":0,"bg_color":"#FF8C26","bg_color02":"#C2BC29","border_side":0,"text":"\uE238","text_font":50}
{"page":1,"id":200,"obj":"btn","x":165,"y":255,"w":45,"h":50,"radius":5,"parentid":80,"bg_opa":255,"bg_grad_dir":0,"bg_color":"#006B04","bg_color02":"#C2BC29","border_side":0,"text":"\uE210","text_font":25}
{"page":1,"id":210,"obj":"btn","x":215,"y":245,"w":45,"h":60,"radius":5,"parentid":80,"bg_opa":255,"bg_grad_dir":0,"bg_color":"#00AD07","bg_color02":"#C2BC29","border_side":0,"text":"\uE210","text_font":35}
{"page":1,"id":220,"obj":"btn","x":265,"y":235,"w":45,"h":70,"radius":5,"parentid":80,"bg_opa":255,"bg_grad_dir":0,"bg_color":"#00FF0B","bg_color02":"#C2BC29","border_side":0,"text":"\uE210","text_font":45}
{"page":1,"comment":"------------------选项卡灯光1"}
{"page":1,"id":230,"obj":"slider","x":60,"y":20,"w":70,"h":230,"parentid":90,"min":0,"max":255,"radius":15,"bg_opa":255,"bg_color":"#6CEBED","bg_grad_dir":0,"bg_opa20":0,"border_side":0,"border_side20":0,"bg_color10":"#DEDEDE","bg_grad_dir10":0,"bg_opa10":255,"hidden":0,"val":50}
{"page":1,"id":231,"obj":"slider","x":200,"y":20,"w":70,"h":230,"parentid":90,"min":2700,"max":6500,"radius":15,"bg_opa":255,"bg_color":"#DEDEDE","bg_grad_color":"#FFA500" ,"bg_grad_dir":1,"bg_grad_stop":350,"bg_opa20":255,"bg_grad_dir10":0,"bg_opa10":0,"border_side10":0,"bg_color20":"#FFFFFF","radius20":50,"bg_grad_dir20":0,"hidden":0,"val":4500}
{"page":1,"comment":"------------------选项卡灯光2"}
{"page":1,"id":232,"obj":"slider","x":60,"y":20,"w":70,"h":230,"parentid":100,"min":0,"max":255,"radius":15,"bg_opa":255,"bg_color":"#E6817E","bg_grad_dir":0,"bg_opa20":0,"border_side":0,"border_side20":0,"bg_color10":"#DEDEDE","bg_grad_dir10":0,"bg_opa10":255,"hidden":0,"val":50}
{"page":1,"id":233,"obj":"slider","x":200,"y":20,"w":70,"h":230,"parentid":100,"min":2700,"max":6500,"radius":15,"bg_opa":255,"bg_color":"#DEDEDE","bg_grad_color":"#FFA500" ,"bg_grad_dir":1,"bg_grad_stop":350,"bg_opa20":255,"bg_grad_dir10":0,"bg_opa10":0,"border_side10":0,"bg_color20":"#FFFFFF","radius20":50,"bg_grad_dir20":0,"hidden":0,"val":4500}
{"page":1,"comment":"------------------选项卡灯光3"}
{"page":1,"id":234,"obj":"slider","x":60,"y":20,"w":70,"h":230,"parentid":110,"min":0,"max":255,"radius":15,"bg_opa":255,"bg_color":"#8A1E94","bg_grad_dir":0,"bg_opa20":0,"border_side":0,"border_side20":0,"bg_color10":"#DEDEDE","bg_grad_dir10":0,"bg_opa10":255,"hidden":0,"val":50}
{"page":1,"id":235,"obj":"slider","x":200,"y":20,"w":70,"h":230,"parentid":110,"min":2700,"max":6500,"radius":15,"bg_opa":255,"bg_color":"#DEDEDE","bg_grad_color":"#FFA500" ,"bg_grad_dir":1,"bg_grad_stop":350,"bg_opa20":255,"bg_grad_dir10":0,"bg_opa10":0,"border_side10":0,"bg_color20":"#FFFFFF","radius20":50,"bg_grad_dir20":0,"hidden":0,"val":4500}
{"page":1,"comment":"------------------语音助手对话标签"}
{"page":1,"id":236,"obj":"label","x":0,"y":400,"w":480,"h":80,"bg_opa":200,"radius":10,"align":"left","mode":"dots","text":"你好","text_font":"hmf30","text_color":"#000000","hidden":1}

openhasp集成:openhasp集成HA配置文件增加如下(configuration.yaml)
openhasp: !include_dir_merge_named openhasp_configs/
config下新建文件openhasp_configs/plate01.yaml

plate01.yaml配置如下:
plate01:
  objects:
    #天气图标
    - obj: "p1b130"
      properties:
        "text": >
          {% if is_state('你的天气实体','sunny') -%}
          {{ "\uE5A8" }}
          {% elif is_state('你的天气实体','partlycloudy') -%}
          {{ "\uE595" }}
          {% elif is_state('你的天气实体','cloudy') -%}
          {{ "\uE590" }}
          {% elif is_state('你的天气实体','rainy') -%}
          {{ "\uE597" }}
          {% elif is_state('你的天气实体','lightningrainy') -%}
          {{ "\uE67E" }}
          {% elif is_state('你的天气实体','hail') -%}
          {{ "\uE592" }}
          {% elif is_state('你的天气实体','snowyrainy') -%}
          {{ "\uE67F" }}
          {% elif is_state('你的天气实体','pouring') -%}
          {{ "\uE596" }}
          {% elif is_state('你的天气实体','snowy') -%}
          {{ "\uE598" }}
          {% elif is_state('你的天气实体','fog') -%}
          {{ "\uE591" }}
          {% elif is_state('你的天气实体','exceptional') -%}
          {{ "\uE595" }}
          {% elif is_state('你的天气实体','windy') -%}
          {{ "\uE59D" }}
          {% endif %}
    #室外温度
    - obj: "p1b140"
      properties:
        "text": "{{ state_attr('你的天气实体','temperature') }}°C"
    #最高温度&日期&农历
    - obj: "p1b150"
      properties:
        "text": "{{ state_attr('你的天气实体','condition_desc') }} {{ state_attr('你的天气实体','temphigh') | int }}/{{ state_attr('你的天气实体','templow') | int }}°C\n{{ state_attr('sensor.holiday','今天')[5:] }}{{ state_attr('sensor.holiday','星期') }}\n{{ state_attr('sensor.holiday','农历')[5:] }}"
    #主卧空调电源开关
    - obj: "p1b21"
      properties:
        "val": '{{ 1 if states("你的空调实体") == "on" else 0 }}'
        "text_color": >
          {% if is_state('你的空调实体', 'cool') %}
          {{ "#346beb" }}
          {%-elif is_state('你的空调实体', 'heat') %}
          {{ "#eb3434" }}
          {%-elif is_state('你的空调实体', 'auto') %}
          {{ "#FF7F27" }}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
      event:
        "up":
          - service: homeassistant.toggle
            entity_id: "你的空调实体"
    #温控标签
    - obj: "p1b20"
      properties:
        "value_color": >
          {% if is_state('你的空调实体', 'cool') %}
          {{ "#346beb" }}
          {%-elif is_state('你的空调实体', 'heat') %}
          {{ "#eb3434" }}
          {%-elif is_state('你的空调实体', 'auto') %}
          {{ "#FF7F27" }}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
    #空调目标温度滑块
    - obj: "p1b170"
      properties:
        "val": >
          {% if state_attr('你的空调实体','temperature') is not none %}
          {{ state_attr('你的空调实体','temperature')}}
          {%- endif %}
        "line_color1": >
          {% if is_state('你的空调实体', 'cool') %}
          {{ "#346beb" }}
          {%-elif is_state('你的空调实体', 'heat') %}
          {{ "#eb3434" }}
          {%-elif is_state('你的空调实体', 'auto') %}
          {{ "#FF7F27" }}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
      event:
        "changed":
          - service: climate.set_temperature
            target:
              entity_id: 你的空调实体
            data:
              temperature: "{{ val }}"
        "up":
          - service: climate.set_temperature
            target:
              entity_id: 你的空调实体
            data:
              temperature: "{{ val }}"
    #空调室温仪表
    - obj: "p1b160"
      properties:
        "val": >
          {% if not (is_state('你的温湿度实体','unavailable') or is_state('你的温湿度实体','unknown')) %}
          {{ states('你的温湿度实体') | int * 10 }}
          {%- endif %}
    #空调模式按钮
    - obj: "p1b180"
      properties:
        "text_color": '{{ "#346beb" if states("你的空调实体") == "cool" else "#9f96b0" }}'
      event:
        "down":
          - service: climate.set_hvac_mode
            target:
              entity_id: 你的空调实体
            data:
              hvac_mode: cool
    - obj: "p1b190"
      properties:
        "text_color": '{{ "#346beb" if states("你的空调实体") == "heat" else "#9f96b0" }}'
      event:
        "down":
          - service: climate.set_hvac_mode
            target:
              entity_id: 你的空调实体
            data:
              hvac_mode: heat
    #空调风速按钮
    - obj: "p1b200"
      properties:
        "text_color": >
          {% if state_attr('你的空调实体','fan_mode') == "low" %}
          {{ "#FFFFFF"}}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
      event:
        "down":
          - service: climate.set_fan_mode
            target:
              entity_id: 你的空调实体
            data:
              fan_mode: low
    - obj: "p1b210"
      properties:
        "text_color": >
          {% if state_attr('你的空调实体','fan_mode') == "medium" %}
          {{ "#FFFFFF"}}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
      event:
        "down":
          - service: climate.set_fan_mode
            target:
              entity_id: 你的空调实体
            data:
              fan_mode: medium
    - obj: "p1b220"
      properties:
        "text_color": >
          {% if state_attr('你的空调实体','fan_mode') == "high" %}
          {{ "#FFFFFF"}}
          {%-else %}
          {{ "#9f96b0" }}
          {% endif %}
      event:
        "down":
          - service: climate.set_fan_mode
            target:
              entity_id: 你的空调实体
            data:
              fan_mode: high
    #灯光1标签
    - obj: "p1b30"
      properties:
        "value_color": '{{ "#F09B59" if states("你的灯光实体1") == "on" else "#9f96b0" }}'
      event:
        "down":
          - service: light.toggle
            target:
              entity_id: 你的灯光实体1

    #灯光1亮度滑块
    - obj: "p1b230"
      properties:
        "val": "{{ state_attr('你的灯光实体1', 'brightness') if state_attr('你的灯光实体1', 'brightness') != None else 0 }}"
      event:
        "changed":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体1
              brightness: "{{ val }}"
        "up":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体1
              brightness: "{{ val }}"
    #灯光1色温滑块
    - obj: "p1b231"
      properties:
        "val": "{{ state_attr('你的灯光实体1', 'color_temp_kelvin') if state_attr('你的灯光实体1', 'color_temp_kelvin') != None else 0 }}"
      event:
        "changed":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体1
              color_temp_kelvin: "{{ val }}"
        "up":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体1
              color_temp_kelvin: "{{ val }}"

    #灯光2标签
    - obj: "p1b40"
      properties:
        "value_color": '{{ "#F09B59" if states("你的灯光实体2") == "on" else "#9f96b0" }}'
      event:
        "down":
          - service: light.toggle
            target:
              entity_id: 你的灯光实体2
    #灯光2亮度滑块
    - obj: "p1b232"
      properties:
        "val": "{{ state_attr('你的灯光实体2', 'brightness') if state_attr('你的灯光实体2', 'brightness') != None else 0 }}"
      event:
        "changed":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体2
              brightness: "{{ val }}"
        "up":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体2
              brightness: "{{ val }}"
    #灯光2色温滑块
    - obj: "p1b233"
      properties:
        "val": "{{ state_attr('你的灯光实体2', 'color_temp_kelvin') if state_attr('你的灯光实体2', 'color_temp_kelvin') != None else 0 }}"
      event:
        "changed":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体2
              color_temp_kelvin: "{{ val }}"
        "up":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体2
              color_temp_kelvin: "{{ val }}"
    #灯光3标签
    - obj: "p1b50"
      properties:
        "value_color": '{{ "#F09B59" if states("你的灯光实体3") == "on" else "#9f96b0" }}'
      event:
        "down":
          - service: light.toggle
            target:
              entity_id: 你的灯光实体3
    #灯光3亮度滑块
    - obj: "p1b234"
      properties:
        "val": "{{ state_attr('你的灯光实体3', 'brightness') if state_attr('你的灯光实体3', 'brightness') != None else 0 }}"
      event:
        "changed":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体3
              brightness: "{{ val }}"
        "up":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体3
              brightness: "{{ val }}"
    #灯光3色温滑块
    - obj: "p1b235"
      properties:
        "val": "{{ state_attr('你的灯光实体3', 'color_temp_kelvin') if state_attr('你的灯光实体3', 'color_temp_kelvin') != None else 0 }}"
      event:
        "changed":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体3
              color_temp_kelvin: "{{ val }}"
        "up":
          - service: light.turn_on
            data:
              entity_id: 你的灯光实体3
              color_temp_kelvin: "{{ val }}"

    #对话内容
    - obj: "p1b236"
      properties:
        "hidden": '{{ 1 if states("你的语音助手实体") == "idle" else 0 }}'
        "text": "{{states('sensor.plate02')}}"
语音助手配置:
substitutions:
  voice_assist_idle_phase_id: '1'
  voice_assist_listening_phase_id: '2'
  voice_assist_thinking_phase_id: '3'
  voice_assist_replying_phase_id: '4'
  voice_assist_not_ready_phase_id: '10'
  voice_assist_error_phase_id: '11'  
  voice_assist_muted_phase_id: '12'


esphome:
  name: 非中文名字
  friendly_name: 非中文名字
    board_build.flash_mode: dio
psram:
  mode:  octal
  speed: 80MHz
esp32:
  board: esp32-s3-devkitc-1
  flash_size: 16MB
  framework:
    type: esp-idf
    sdkconfig_options:
        CONFIG_ESP32_S3_BOX_BOARD: "y"
        CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM: "16"
        CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM: "512"
        CONFIG_TCPIP_RECVMBOX_SIZE: "512"
        CONFIG_TCP_SND_BUF_DEFAULT: "65535"
        CONFIG_TCP_WND_DEFAULT: "512000"
        CONFIG_TCP_RECVMBOX_SIZE: "512"
logger:


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
api:
   encryption:
     key: "12345"
  
ota:
  password: "1234"
  platform: esphome
esp32_ble:
  enable_on_boot: false

button:
  - platform: restart
    name: "Restart"
    id: but_rest
external_components:
  - source:
      type: local
      path: mycomponents
      # ref: dev-next
    components: [ adf_pipeline, i2s_audio ]
    # refresh: 0s 
#上边是两个esphome外部组件

adf_pipeline:
  - platform: i2s_audio
    type: audio_out
    id: adf_spk
    i2s_audio_id: i2s_out
    i2s_dout_pin: GPIO12
    
  - platform: i2s_audio
    type: audio_in
    id: adf_mic
    i2s_audio_id: i2s_in
    i2s_din_pin: GPIO4
    channel: left
    sample_rate: 16000
    bits_per_sample: 16bit
    pdm: false
microphone:
  - platform: adf_pipeline
    id: adf_microphone
    gain_log2: 3
    keep_pipeline_alive: false
    pipeline:
      - adf_mic
      - self
i2s_audio:
  - id: i2s_in
    i2s_lrclk_pin: GPIO01
    i2s_bclk_pin: GPIO02
  - id: i2s_out
    i2s_lrclk_pin: GPIO15
    i2s_bclk_pin: GPIO13

media_player:
  - platform: adf_pipeline
    id: adf_media_player
    name: Media player
    keep_pipeline_alive: false
    internal: false
    pipeline:
      - self
      - adf_spk

voice_assistant:
  id: va
  microphone: adf_microphone
  media_player: adf_media_player
  use_wake_word: false
  noise_suppression_level: 2 #4
  auto_gain: 31dBFS # 31dBFS
  volume_multiplier: 2 # 8.0

  on_listening:
    - lambda: id(voice_assistant_phase) = ${voice_assist_listening_phase_id};
    - text_sensor.template.publish:
        id: text_request
        state: "。。。"
    - text_sensor.template.publish:
        id: text_response
        state: "。。。"

  on_stt_vad_end:
    - lambda: id(voice_assistant_phase) = ${voice_assist_thinking_phase_id};
  on_stt_end:
    - text_sensor.template.publish:
        id: text_request
        state: !lambda return x;

  on_tts_start:
    - lambda: id(voice_assistant_phase) = ${voice_assist_replying_phase_id};
    - text_sensor.template.publish:
       id: text_response
       state: !lambda return x;

  on_end:
    - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
    

globals:
  - id: init_in_progress
    type: bool
    restore_value: no
    initial_value: 'true'
  - id: voice_assistant_phase
    type: int
    restore_value: no
    initial_value: ${voice_assist_not_ready_phase_id}

text_sensor:
  - id: text_request
    platform: template
    name: 对话内容
    on_value:
      lambda: |-
        if(id(text_request).state.length()>100) {
          std::string name = id(text_request).state.c_str();
          std::string truncated = esphome::str_truncate(name.c_str(),99);
          id(text_request).state = (truncated+"...").c_str();
        }
  - id: text_response
    platform: template
    name: 对话内容
    on_value:
      lambda: |-
        if(id(text_response).state.length()>100) {
          std::string name = id(text_response).state.c_str();
          std::string truncated = esphome::str_truncate(name.c_str(),99);
          id(text_response).state = (truncated+"...").c_str();
        }

binary_sensor:
  - platform: gpio
    name: Click_to_Converse
    id: Click_to_Converse
    pin:
      number: 21  
    on_press:
      - homeassistant.service:
         service: media_player.play_media
         data:
           entity_id: media_player.你的媒体播放器实体
           media_content_id: "media-source://media_source/local/wozai.mp3" 
           media_content_type: music
      - if:
          condition: 
            - voice_assistant.is_running
          then:
            - voice_assistant.stop:
          else:
            - delay: 800ms
            - voice_assistant.start:
ASR-PRO代替唤醒词(这个模块识别很好)接21gpio帮助一键通唤醒ASR-PRO不需要讲话:

                               
登录/注册后可看大图

语音转文字:官方推荐的whisper需要显卡才能发挥,论坛还有国内的方案没有测试硬件需求大家可以论坛搜一下
对话代理:官方的必须一个字不能错。qwen2.5需要显卡才能用。论坛内有白嫖国内AI服务商的教程。或者用谷歌和GPT
文字转语音:edgeTTS免费速度还可以。其它tts需要显卡可以自定义音色比如最近比较火的雷布斯的音色,不过没啥用!

以上的难点在于组装和拆焊还有焊接,那位坛友拿走优化一下改成对插基本没有什么难度。







评分

参与人数 2金钱 +20 收起 理由
book123 + 10 高手,这是高手!需要啊,请把资料放出!.
DDDear + 10 高手,这是高手!

查看全部评分

回复

使用道具 举报

21

主题

525

帖子

3241

积分

论坛元老

Rank: 8Rank: 8

积分
3241
金钱
2716
HASS币
30
发表于 2024-6-29 01:19:52 | 显示全部楼层
diy的语音助手,总感觉有两个问题
一个大问题好像是拾音?像是小爱pro上有6个还是8个拾音麦,基本实现每个方向都能唤醒,但是这种小板,朝向比较狭窄,不知道拾音唤醒灵敏度如何?
另一个就是家里有多个的话,会不会出现同事唤醒的情况……
回复

使用道具 举报

13

主题

619

帖子

3207

积分

论坛元老

HomeAssistant

Rank: 8Rank: 8

积分
3207
金钱
2583
HASS币
20
发表于 2024-6-29 11:12:56 | 显示全部楼层
wdmywm3 发表于 2024-6-29 01:19
diy的语音助手,总感觉有两个问题
一个大问题好像是拾音?像是小爱pro上有6个还是8个拾音麦,基本实 ...

我用这个集成https://github.com/AlexxIT/StreamAssist 和 IPCamera在旧手机上做了一个rtsp接到ha,拾音效果还不错,唤醒词总是误触发
回复

使用道具 举报

15

主题

186

帖子

1023

积分

金牌会员

Rank: 6Rank: 6

积分
1023
金钱
837
HASS币
0
 楼主| 发表于 2024-6-29 12:39:22 | 显示全部楼层
wdmywm3 发表于 2024-6-29 01:19
diy的语音助手,总感觉有两个问题
一个大问题好像是拾音?像是小爱pro上有6个还是8个拾音麦,基本实 ...

全向麦克风拾音范围很小3米左右极限了。商用的都是远场阵列麦克风。阵列麦克风塞不进去的。唤醒积极性调高了容易误触发,低了有时候喊不醒。micro wake word 是一个很好方案但是不支持中文。协同唤醒这个不太了解方案。
回复

使用道具 举报

5

主题

233

帖子

4484

积分

元老级技术达人

积分
4484
金钱
4236
HASS币
40
发表于 2024-8-27 11:30:31 | 显示全部楼层
大佬能给个电源底板和麦克风版的资源么...我也是同款屏幕
回复

使用道具 举报

15

主题

186

帖子

1023

积分

金牌会员

Rank: 6Rank: 6

积分
1023
金钱
837
HASS币
0
 楼主| 发表于 2024-9-18 14:58:49 | 显示全部楼层
81795791 发表于 2024-8-27 11:30
大佬能给个电源底板和麦克风版的资源么...我也是同款屏幕

可以的,我需要整理一下。你私信一下我。
回复

使用道具 举报

15

主题

186

帖子

1023

积分

金牌会员

Rank: 6Rank: 6

积分
1023
金钱
837
HASS币
0
 楼主| 发表于 2024-10-11 15:21:42 | 显示全部楼层
回复

使用道具 举报

0

主题

17

帖子

144

积分

注册会员

Rank: 2

积分
144
金钱
127
HASS币
0
发表于 2024-12-19 10:28:59 | 显示全部楼层
DDDear 发表于 2024-6-29 11:12
我用这个集成https://github.com/AlexxIT/StreamAssist 和 IPCamera在旧手机上做了一个rtsp接到ha,拾音 ...

求大佬,能不能出个简易教程,琢磨两天了,手机也装了摄像头软件,死活连不到ha
回复

使用道具 举报

7

主题

167

帖子

653

积分

高级会员

Rank: 4

积分
653
金钱
486
HASS币
0
发表于 2024-12-19 10:46:16 | 显示全部楼层
收藏起来,目前动手能力不够
总为浮云能避日,长安不见使人愁
回复

使用道具 举报

13

主题

619

帖子

3207

积分

论坛元老

HomeAssistant

Rank: 8Rank: 8

积分
3207
金钱
2583
HASS币
20
发表于 2024-12-19 12:01:37 | 显示全部楼层
zxlfly1 发表于 2024-12-19 10:28
求大佬,能不能出个简易教程,琢磨两天了,手机也装了摄像头软件,死活连不到ha ...

时间比较长了,一直没用,我整理下几个坑你排查下:
1.安装配置唤醒词
2.安装配置STT
3.安装配置TTS
4.配置好语音助手
至少上面的2 3 4通过app测试成功
5.IPCamera 开启rtsp和开启音频并且不要关闭视频,最好测试下rtsp
6.配置Stream Assist,填入rtsp连接
7.尝试唤醒词唤醒
有问题查看日志看看报错吧
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-12-28 01:03 , Processed in 1.856625 second(s), 35 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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