gnumpi / esphome_matrixio

ESPHome Component for MatrixIO Devices
Other
10 stars 4 forks source link

ERROR Unable to load component matrixio.adf_pipeline #19

Open WhiteSockedDancer opened 1 month ago

WhiteSockedDancer commented 1 month ago

Hey @gnumpi, i got the next problem:

I wanted to try your example of the adf voice assistant pipeline, but it seems like i cant compile the firmware: ERROR Unable to load component matrixio.adf_pipeline

image

Log when trying to install:

INFO ESPHome 2024.5.5
INFO Reading configuration /config/matrix_voice.yaml...
ERROR Unable to load component matrixio.adf_pipeline:
Traceback (most recent call last):
  File "/esphome/esphome/loader.py", line 176, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/config/.esphome/external_components/2a88a3c3/esphome/components/matrixio/adf_pipeline/__init__.py", line 32, in <module>
    CONFIG_SCHEMA_OUT = esp_adf.ADF_COMPONENT_SCHEMA.extend(
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'esphome.components.adf_pipeline' has no attribute 'ADF_COMPONENT_SCHEMA'
ERROR Unable to load component matrixio.adf_pipeline:
Traceback (most recent call last):
  File "/esphome/esphome/loader.py", line 176, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/config/.esphome/external_components/2a88a3c3/esphome/components/matrixio/adf_pipeline/__init__.py", line 32, in <module>
    CONFIG_SCHEMA_OUT = esp_adf.ADF_COMPONENT_SCHEMA.extend(
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'esphome.components.adf_pipeline' has no attribute 'ADF_COMPONENT_SCHEMA'
Failed config

adf_pipeline.matrixio: [source /config/matrix_voice.yaml:46]

  Platform not found: 'adf_pipeline.matrixio'.
  platform: matrixio
  id: adf_matrix_mics
  type: source
  sampling_rate: 16000
adf_pipeline.matrixio: [source /config/matrix_voice.yaml:51]

  Platform not found: 'adf_pipeline.matrixio'.
  platform: matrixio
  id: adf_matrix_out
  type: sink
  audio_out: headphone
  volume: 80

my yaml:

external_components:
  - source:
      type: git
      url: https://github.com/gnumpi/esphome_matrixio
      ref: main
  - source:
      type: git
      url: https://github.com/gnumpi/esphome_audio
      ref: main
    components: [ adf_pipeline ]

esphome:
  name: matrixio-voice
  friendly_name: Matrix Voice
  comment: 'Matrix Voice Lampe'

esp32:
  board: esp32dev
  framework:
    type: esp-idf
    version: recommended

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  domain: !secret wifi_domain
  fast_connect: true

logger:

ota:
  password: !secret ota_password

api:

spi:
  clk_pin:  GPIO32
  mosi_pin: GPIO33
  miso_pin: GPIO21

matrixio:
  id: matrixio_dev
  cs_pin: GPIO23

adf_pipeline:
  - platform: matrixio
    id: adf_matrix_mics
    type: source
    sampling_rate: 16000

  - platform: matrixio
    id: adf_matrix_out
    type: sink
    audio_out: headphone
    volume: 80

microphone:
  - platform: adf_pipeline
    id: adf_matrixio_microphone
    pipeline:
      - adf_matrix_mics
      - self

media_player:
  - platform: adf_pipeline
    id: adf_media_player
    name: matrixio_media_player
    internal: false
    pipeline:
      - self
      - adf_matrix_out

#Everloop
light:
  - platform: matrixio
    name: everloop
    id: everloop    
    default_transition_length: 0s

    effects:
      - pulse:
          name: "Slow Pulse"
          transition_length: 250ms
          update_interval: 250ms
          min_brightness: 50%
          max_brightness: 100%

      - pulse:
          name: "Fast Pulse"
          transition_length: 100ms
          update_interval: 100ms
          min_brightness: 50%
          max_brightness: 100%

      - addressable_lambda:
          name: "Looping Dot"
          update_interval: 100ms
          lambda: |-
            // it.size() - Number of LEDs
            // it[num] - Access the LED at index num.
            // Set the LED at num to the given r, g, b values
            // it[num] = Color(r, g, b);
            // Get the color at index num (Color instance)
            // it[num].get();

            // Example: Simple color wipe
            for (int i = it.size() - 1; i > 0; i--) {
              it[i] = it[i - 1].get();
            }
            it[0] = Color(0,0,.4,0);

#VoiceAssistant
# credits go to @jlpouffier
# based on:
# https://github.com/jlpouffier/voice-assistant-esphome-tutorial/tree/main
substitutions:
 # node_name: matrixio-voice
  # Phases of the Voice Assistant
  # IDLE: The voice assistant is ready to be triggered by a wake-word
  voice_assist_idle_phase_id: '1'
  # LISTENING: The voice assistant is ready to listen to a voice command (after being triggered by the wake word)
  voice_assist_listening_phase_id: '2'
  # THINKING: The voice assistant is currently processing the command
  voice_assist_thinking_phase_id: '3'
  # REPLYING: The voice assistant is replying to the command
  voice_assist_replying_phase_id: '4'
  # NOT_READY: The voice assistant is not ready 
  voice_assist_not_ready_phase_id: '10'
  # ERROR: The voice assistant encountered an error
  voice_assist_error_phase_id: '11'  
  # MUTED: The voice assistant is muted and will not reply to a wake-word
  voice_assist_muted_phase_id: '12'

globals:
  # Global initialisation variable. Initialized to true and set to false once everything is connected. Only used to have a smooth "plugging" experience
  - id: init_in_progress
    type: bool
    restore_value: no
    initial_value: 'true'
  # Global variable tracking the phase of the voice assistant (defined above). Initialized to not_ready
  - id: voice_assistant_phase
    type: int
    restore_value: no
    initial_value: ${voice_assist_not_ready_phase_id}

voice_assistant:
  id: va
  microphone: adf_matrixio_microphone
  media_player: adf_media_player
  use_wake_word: true  
  # When the voice assistant connects to HA:
  # Set init_in_progress to false (Initialization is over).
  # If the switch is on, start the voice assistant
  # In any case: Set the correct phase and run the script to refresh the LED status
  on_client_connected:
    - lambda: id(init_in_progress) = false; 
    - if:
        condition:
          switch.is_on: use_wake_word
        then:
          - voice_assistant.start_continuous: 
          - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
        else:
          - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id};
    - script.execute: control_led

  # When the voice assistant disconnects to HA: 
  # Stop the voice assistant
  # Set the correct phase and run the script to refresh the LED status
  on_client_disconnected:
    - lambda: id(voice_assistant_phase) = ${voice_assist_not_ready_phase_id};  
    - voice_assistant.stop
    - script.execute: control_led

  # When the voice assistant starts to listen: Set the correct phase and run the script to refresh the LED status
  on_listening:
    - lambda: id(voice_assistant_phase) = ${voice_assist_listening_phase_id};
    - script.execute: control_led

  # When the voice assistant starts to think: Set the correct phase and run the script to refresh the LED status
  on_stt_vad_end:
    - lambda: id(voice_assistant_phase) = ${voice_assist_thinking_phase_id};
    - script.execute: control_led

  # When the voice assistant starts to reply: Set the correct phase and run the script to refresh the LED status
  on_tts_start:
    - lambda: id(voice_assistant_phase) = ${voice_assist_replying_phase_id};
    - script.execute: control_led

  # When the voice assistant finished to reply: Set the correct phase and run the script to refresh the LED status
  on_tts_end:
    - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
    - script.execute: control_led

  # When the voice assistant encounters an error: 
  # Set the error phase and run the script to refresh the LED status
  # Wait 1 second and set the correct phase (idle or muted depending on the state of the switch) and run the script to refresh the LED status 
  on_error:
    - if:
        condition:
          lambda: return !id(init_in_progress);
        then:
          - lambda: id(voice_assistant_phase) = ${voice_assist_error_phase_id};  
          - script.execute: control_led
          - delay: 1s
          - if:
              condition:
                switch.is_on: use_wake_word
              then:
                - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
              else:
                - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id};
          - script.execute: control_led

switch:
  - platform: template
    name: Enable Voice Assistant
    id: use_wake_word
    optimistic: true
    restore_mode: RESTORE_DEFAULT_ON
    icon: mdi:assistant
    # When the switch is turned on (on Home Assistant):
    # Start the voice assistant component
    # Set the correct phase and run the script to refresh the LED status
    on_turn_on:
      - if:
          condition:
            lambda: return !id(init_in_progress);
          then:      
            - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id};
            - if:
                condition:
                  not:
                    - voice_assistant.is_running
                then:
                  - voice_assistant.start_continuous
            - script.execute: control_led

    # When the switch is turned off (on Home Assistant):
    # Stop the voice assistant component
    # Set the correct phase and run the script to refresh the LED status
    on_turn_off:
      - if:
          condition:
            lambda: return !id(init_in_progress);
          then:      
            - voice_assistant.stop
            - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id};
            - script.execute: control_led

script:
  # Master script controlling the LED, based on different conditions: initialization in progress, wifi and API connected, and the current voice assistant phase.
  # For the sake of simplicity and re-usability, the script calls child scripts defined below.
  # This script will be called every time one of these conditions is changing.
  - id: control_led
    then:
      - if:
          condition:
            lambda: return !id(init_in_progress);
          then:
            - if:
                condition:
                  wifi.connected:
                then:
                  - if:
                      condition:
                        api.connected:
                      then:
                        - lambda: |
                            switch(id(voice_assistant_phase)) {
                              case ${voice_assist_listening_phase_id}:
                                id(control_led_voice_assist_listening_phase).execute();
                                break;
                              case ${voice_assist_thinking_phase_id}:
                                id(control_led_voice_assist_thinking_phase).execute();
                                break;
                              case ${voice_assist_replying_phase_id}:
                                id(control_led_voice_assist_replying_phase).execute();
                                break;
                              case ${voice_assist_error_phase_id}:
                                id(control_led_voice_assist_error_phase).execute();
                                break;
                              case ${voice_assist_muted_phase_id}:
                                id(control_led_voice_assist_muted_phase).execute();
                                break;
                              case ${voice_assist_not_ready_phase_id}:
                                id(control_led_voice_assist_not_ready_phase).execute();
                                break;
                              default:
                                id(control_led_voice_assist_idle_phase).execute();
                                break;
                            }
                      else:
                        - script.execute: control_led_no_ha_connection_state
                else:
                  - script.execute: control_led_no_ha_connection_state
          else:
            - script.execute: control_led_init_state

  # Script executed during initialisation: In this example: Turn the LED in green with a slow pulse 🟢
  - id: control_led_init_state
    then:
      - light.turn_on:
          id: everloop
          blue: 0%
          red: 0%
          green: 100%
          effect: "Fast Pulse"

  # Script executed when the device has no connection to Home Assistant: In this example: Turn off the LED 
  - id: control_led_no_ha_connection_state
    then:
      - light.turn_off:
          id: everloop  

  # Script executed when the voice assistant is idle (waiting for a wake word): In this example: Turn the LED in white with 20% of brightness ⚪
  - id: control_led_voice_assist_idle_phase
    then:
      - light.turn_on:
          id: everloop
          blue: 100%
          red: 100%
          green: 100%
          brightness: 20%
          effect: "none"

  # Script executed when the voice assistant is listening to a command: In this example: Turn the LED in blue with a slow pulse 🔵
  - id: control_led_voice_assist_listening_phase
    then:
      - light.turn_on:
          id: everloop
          blue: 100%
          red: 0%
          green: 0%
          effect: "Slow Pulse"

  # Script executed when the voice assistant is processing the command: In this example: Turn the LED in blue with a fast pulse 🔵         
  - id: control_led_voice_assist_thinking_phase
    then:
      - light.turn_on:
          id: everloop
          blue: 100%
          red: 0%
          green: 0%
          effect: "Fast Pulse"

  # Script executed when the voice assistant is replying to a command: In this example: Turn the LED in blue, solid (no pulse) 🔵         
  - id: control_led_voice_assist_replying_phase
    then:
      - light.turn_on:
          id: everloop
          blue: 100%
          red: 0%
          green: 0%
          brightness: 100%
          effect: "none"

  # Script executed when the voice assistant encounters an error: In this example: Turn the LED in red, solid (no pulse) 🔴        
  - id: control_led_voice_assist_error_phase
    then:
      - light.turn_on:
          id: everloop
          blue: 0%
          red: 100%
          green: 0%
          brightness: 100%
          effect: "none"

  # Script executed when the voice assistant is muted: In this example: Turn off the LED 
  - id: control_led_voice_assist_muted_phase
    then:
      - light.turn_off:
          id: everloop

  # Script executed when the voice assistant is not ready: In this example: Turn off the LED 
  - id: control_led_voice_assist_not_ready_phase
    then:
      - light.turn_off:
          id: everloop

i also tried it with local sources but got the same error.

external_components:
  - source:
      type: local
      path: esphome_matrixio/esphome/components/
  - source:
      type: local
      path: esphome_audio/esphome/components/
    components: [ adf_pipeline ]
gnumpi commented 1 month ago

thank you for reporting, actually I am not surprised. I haven't touched the matrixio code in a while and continued the work on adf_pipeline quite a bit in the meantime, so I have to align the codes again. I will do it...

WhiteSockedDancer commented 1 month ago

thx for looking into it! If i can help in any way just reach out to me! :)

WhiteSockedDancer commented 3 weeks ago

Any news on this? I would love to use my matrix-voice also for playing some sounds and it seems like i already saved my posted config and didnt make a backup on my actual working one.. Don't want to cause any stress, just want to know if it is worth to rebuild my old config or if an update is just around the corner? If i can help or test anything, feel free to ask.