# =====================================================================
#  示例 0：ESP32-S3-RLCD-4.2 全功能配置（含本地语音助手）
#  覆盖：ST7305 显示 / SHTC3 / 电池监测 / 双麦 + 扬声器 / Hey Jarvis
#  说明：需要外接扬声器与麦克风才能完整使用音频部分。
# =====================================================================

esphome:
  name: esp32-s3-rlcd-42
  friendly_name: ESP32-S3-RLCD-4.2
  on_boot:
    - priority: -100
      then:
        - component.update: my_display

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf
    components:
      - espressif/esp-nn==1.1.2

psram:
  mode: octal
  speed: 80MHz

external_components:
  - source: github://kylehase/ESPHome-ST7305-RLCD
    components: [st7305_rlcd]

logger:
  level: INFO

api:
  encryption:
    key: "7J7XVVoREEncoG39FrOxlb/ZVMRS/u7RmTc4WK2Ej7w="

ota:
  - platform: esphome
    password: "d9a7ee09077e2b8c27f2563e475e66ea"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Esp32-S3-Rlcd-42"
    password: "Wa3PMQZVj5kn"

captive_portal:

# ---------- 总线 ----------
i2c:
  - id: bus_a
    sda: GPIO13
    scl: GPIO14
    scan: true

spi:
  - id: spi_lcd
    clk_pin: GPIO11
    mosi_pin: GPIO12

i2s_audio:
  - id: i2s_shared
    i2s_lrclk_pin: GPIO45
    i2s_bclk_pin: GPIO9
    i2s_mclk_pin: GPIO16

# ---------- 音频编解码 ----------
audio_dac:
  - platform: es8311
    id: es8311_dac
    bits_per_sample: 16bit
    sample_rate: 16000

audio_adc:
  - platform: es7210
    id: es7210_adc
    bits_per_sample: 16bit
    sample_rate: 16000
    mic_gain: 24dB

# ---------- 扬声器与麦克风 ----------
speaker:
  - platform: i2s_audio
    id: i2s_audio_speaker
    i2s_audio_id: i2s_shared
    i2s_dout_pin: GPIO8
    dac_type: external
    audio_dac: es8311_dac
    channel: left
    sample_rate: 16000
    bits_per_sample: 16bit
    buffer_duration: 100ms
    timeout: never

  - platform: resampler
    id: announcement_speaker
    output_speaker: i2s_audio_speaker

microphone:
  - platform: i2s_audio
    id: va_mic
    i2s_audio_id: i2s_shared
    i2s_din_pin: GPIO10
    adc_type: external
    sample_rate: 16000
    bits_per_sample: 16bit
    pdm: false

# ---------- 字体 ----------
font:
  - file: "gfonts://Roboto"
    id: roboto
    size: 20

# ---------- 显示屏 ----------
display:
  - platform: st7305_rlcd
    id: my_display
    model: WAVESHARE_400X300
    width: 400
    height: 300
    cs_pin: GPIO40
    dc_pin: GPIO5
    reset_pin: GPIO41
    data_rate: 1MHz
    update_interval: 30s
    lambda: |-
      it.printf(10, 10,  id(roboto), "Temp: %.1f C",  id(temp_sensor).state);
      it.printf(10, 40,  id(roboto), "Hum:  %.1f %%", id(hum_sensor).state);
      it.printf(10, 70,  id(roboto), "Bat:  %.2f V",  id(bat_voltage).state);
      it.printf(10, 100, id(roboto), "Lvl:  %.0f %%", id(bat_level).state);
      it.printf(10, 260, id(roboto), "%s",            id(ha_status).state.c_str());

text_sensor:
  - platform: template
    id: ha_status
    name: "HA Status Text"
    lambda: |-
      if (id(va).is_running()) return {"Listening..."};
      else                     return {"Idle"};
    update_interval: 1s

# ---------- 传感器 ----------
sensor:
  - platform: shtcx
    address: 0x70
    i2c_id: bus_a
    update_interval: 60s
    temperature:
      name: "Temperature"
      id: temp_sensor
    humidity:
      name: "Humidity"
      id: hum_sensor

  - platform: adc
    id: bat_voltage
    name: "Battery Voltage"
    pin: GPIO4
    attenuation: 12db
    update_interval: 60s
    filters:
      - multiply: 3.0

  - platform: copy
    source_id: bat_voltage
    id: bat_level
    name: "Battery Level"
    unit_of_measurement: "%"
    filters:
      - calibrate_linear:
          - 2.5 -> 0.0
          - 4.2 -> 100.0
      - clamp:
          min_value: 0
          max_value: 100

  - platform: wifi_signal
    name: "WiFi Signal"
    update_interval: 60s

  - platform: uptime
    name: "Uptime"

# ---------- 媒体播放、唤醒词、语音助手 ----------
media_player:
  - platform: speaker
    id: speaker_media_player
    name: None
    announcement_pipeline:
      speaker: announcement_speaker
      format: FLAC
      sample_rate: 16000
      num_channels: 1
    files:
      - id: wake_word_triggered_sound
        file: https://github.com/esphome/home-assistant-voice-pe/raw/dev/sounds/wake_word_triggered.flac

micro_wake_word:
  id: mww
  microphone:
    microphone: va_mic
    channels: 0
    gain_factor: 4
  vad:
  models:
    - model: hey_jarvis
  on_wake_word_detected:
    - media_player.speaker.play_on_device_media_file:
        media_file: wake_word_triggered_sound
        announcement: true
    - delay: 300ms
    - voice_assistant.start:
        wake_word: !lambda return wake_word;

voice_assistant:
  id: va
  microphone:
    microphone: va_mic
    channels: 0
    gain_factor: 4
  media_player: speaker_media_player
  micro_wake_word: mww
  use_wake_word: false
  noise_suppression_level: 2
  auto_gain: 31dBFS
  on_error:
    - script.execute: restart_mww
  on_end:
    - script.execute: restart_mww
  on_client_connected:
    - micro_wake_word.start:
  on_client_disconnected:
    - micro_wake_word.stop:

script:
  - id: restart_mww
    then:
      - delay: 500ms
      - wait_until:
          not:
            media_player.is_announcing:
      - wait_until:
          not:
            speaker.is_playing:
              id: i2s_audio_speaker
      - delay: 200ms
      - micro_wake_word.start:

# ---------- 开关 ----------
switch:
  - platform: gpio
    name: "Speaker Enable"
    pin: GPIO46
    restore_mode: RESTORE_DEFAULT_ON

  - platform: template
    name: "Mute"
    id: mute_switch
    icon: mdi:microphone-off
    optimistic: true
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - micro_wake_word.stop:
      - voice_assistant.stop:
    on_turn_off:
      - if:
          condition:
            switch.is_on: use_wake_word_switch
          then:
            - micro_wake_word.start:

  - platform: template
    name: "Use Wake Word"
    id: use_wake_word_switch
    icon: mdi:chat-processing
    optimistic: true
    restore_mode: RESTORE_DEFAULT_ON
    on_turn_on:
      - if:
          condition:
            not:
              switch.is_on: mute_switch
          then:
            - micro_wake_word.start:
    on_turn_off:
      - micro_wake_word.stop:

# ---------- 按键 ----------
binary_sensor:
  - platform: gpio
    name: "Boot Button"
    pin:
      number: GPIO0
      inverted: true
      mode: INPUT
    on_press:
      - voice_assistant.start:
    on_release:
      - voice_assistant.stop:

  - platform: gpio
    name: "Key Button"
    pin:
      number: GPIO18
      inverted: true
      mode: INPUT
    on_press:
      - switch.toggle: mute_switch
    on_multi_click:
      - timing:
          - ON for at least 1.5s
        then:
          - component.update: my_display

# ---------- TTS 音量 ----------
number:
  - platform: template
    name: "TTS Volume"
    id: tts_volume
    icon: mdi:volume-high
    min_value: 0
    max_value: 100
    step: 5
    initial_value: 75
    optimistic: true
    restore_value: true
    set_action:
      then:
        - media_player.volume_set:
            id: speaker_media_player
            volume: !lambda "return x / 100.0;"
