OLED 1,5 Zoll Display 128x128, IIC / I2C, SH1107

Moin Moin,

Ich habe eine Muse Luxe V2 Box als Satelite in meinem Homeassistant.
Konfiguriert habe ich das Teil mit espHome.
Läuft auch zufriedenstellend.

Jetzt habe ich mir ein kleines Display besorgt um mir folgendes anzeigen zu lassen:
WLAN Empfang
Batrteriestatus
und das aktuell abgespielte Lied, oder Radiostream.

Leider bekomme ich das nict richtig in meine yml integriert.

Hier ist meine yml:

substitutions:
  name: muse-luxe
  friendly_name: Voice Badezimmer
  P_starting: "0"
  P_waiting: "1"
  P_playing: "2"
  P_listening: "3"
  P_answering: "4"

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  min_version: 2025.2.0
  name_add_mac_suffix: false
  platformio_options:
    board_build.flash_mode: dio
    board_build.arduino.memory_type: qio_opi
  project:
    name: raspiaudio.voice-assistant
    version: "2025.3.0"
  on_boot:
    priority: -100.0
    then:
      - output.turn_on: dac_mute
      - lambda: id(muteH) = true;
      - lambda: id(phase) = 0;
      - script.execute: update_led

external_components:
  - source: github://RASPIAUDIO/esphomeLuxe@main
    components: [es8388]
    refresh: 0s

esp32:
  board: esp-wrover-kit
  flash_size: 4MB
  partitions: luxe_partitions.csv
  framework:
    type: esp-idf
    version: recommended
    sdkconfig_options:
      CONFIG_ESP_CONSOLE_USB_CDC: "n"
      CONFIG_ESP_CONSOLE_UART_DEFAULT: "y"
      CONFIG_ESP_CONSOLE_UART_NUM: "0"
      CONFIG_ESP_CONSOLE_UART_BAUDRATE: "115200"

micro_wake_word:
  id: mww
  microphone: luxe_mic
  stop_after_detection: false
  models:
    - model: https://github.com/kahrendt/microWakeWord/releases/download/okay_nabu_20241226.3/okay_nabu.json
      id: okay_nabu
    - model: hey_jarvis
      id: hey_jarvis
    - model: hey_mycroft
      id: hey_mycroft
    - model: https://github.com/kahrendt/microWakeWord/releases/download/stop/stop.json
      id: stop
      internal: true
  on_wake_word_detected:
    - voice_assistant.start:
        wake_word: !lambda return wake_word;

ota:
  - platform: esphome
    id: ota_esphome
  - platform: http_request
    id: ota_http_request

update:
  - platform: http_request
    id: update_http_request
    name: Firmware
    source: https://raw.githubusercontent.com/RASPIAUDIO/esphomeLuxe/main/manifest_update.json

http_request:
api:
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  power_save_mode: none
  output_power: 15
  ap:
    ssid: "Raspiaudio-luxe"
    password: "12345678"
captive_portal:
improv_serial:

logger:
  level: DEBUG
  baud_rate: 115200
  hardware_uart: UART0
  logs:
    media_player: WARN

es8388:
  id: my_es8388

psram:
  mode: quad
  speed: 80MHz

i2c:
  sda: GPIO18
  scl: GPIO23

output:
  - platform: gpio
    id: dac_mute
    pin:
      number: GPIO21
      inverted: true
      mode:
        output: true

globals:
  - id: Vol
    type: float
    initial_value: '0.6'
  - id: phase
    type: int
    initial_value: '0'
  - id: mute
    type: bool
    initial_value: 'false'
  - id: muteH
    type: bool
    initial_value: 'false'
  - id: last_led_phase
    type: int
    initial_value: '-1'
  - id: audio_active
    type: bool
    initial_value: 'false'
  - id: audio_started
    type: bool
    initial_value: 'false'
  - id: last_volume_cmd
    type: float
    initial_value: '-1.0'

font:
  - file: "gfonts://Roboto"
    id: font_small
    size: 10

display:
  - platform: ssd1306_i2c
    id: my_display
    model: "SH1107 128x128"
    address: 0x3C
    lambda: |-
      it.printf(0, 0, id(font_small), "Muse Luxe V2");
      it.printf(0, 10, id(font_small), "WLAN: %s", id(wifi_status).state ? "Verbunden" : "Getrennt");
      it.printf(0, 20, id(font_small), "Batterie: %d%%", id(battery_percent).state);
      if (id(luxe_media_player).is_playing()) {
        it.printf(0, 30, id(font_small), "Spielt: %s", id(now_playing).state.c_str());
      } else {
        it.printf(0, 30, id(font_small), "Kein Titel");
      }

interval:
  - interval: 0.1s
    then:
      - if:
          condition:
            - speaker.is_stopped:
          then:
            - if:
                condition:
                  - not:
                      lambda: 'return(id(muteH));'
                then:
                  - output.turn_on: dac_mute
                  - lambda: id(muteH) = true;
                  - logger.log: "====> hardware mute"
      - if:
          condition:
            - speaker.is_playing:
          then:
            - if:
                condition:
                  - lambda: 'return(id(muteH));'
                then:
                  - output.turn_off: dac_mute
                  - lambda: id(muteH) = false;
                  - logger.log: "====> hardware unmute"
      - if:
          condition:
            and:
              - lambda: 'return id(audio_active) && !id(audio_started);'
              - speaker.is_playing:
          then:
            - lambda: id(audio_started) = true;
  - interval: 1s
    then:
      - display.page.show: my_display

sensor:
  - platform: adc
    pin: GPIO33
    name: Battery voltage
    device_class: voltage
    unit_of_measurement: "V"
    accuracy_decimals: 2
    state_class: measurement
    entity_category: diagnostic
    update_interval: 15s
    attenuation: auto
    filters:
      - multiply: 2
      - exponential_moving_average:
          alpha: 0.2
          send_every: 2
      - delta: 0.002
    on_value:
      then:
        - sensor.template.publish:
            id: battery_percent
            state: !lambda "return x;"
  - platform: template
    name: Battery
    id: battery_percent
    device_class: battery
    unit_of_measurement: "%"
    accuracy_decimals: 0
    state_class: measurement
    entity_category: diagnostic
    update_interval: 15s
    filters:
      - calibrate_polynomial:
          degree: 3
          datapoints:
            - 4.58 -> 100.0
            - 4.5 -> 97.1
            - 4.47 -> 94.2
            - 4.44 -> 88.4
            - 4.42 -> 82.7
            - 4.41 -> 76.9
            - 4.41 -> 71.1
            - 4.37 -> 65.3
            - 4.35 -> 59.5
            - 4.31 -> 53.8
            - 4.28 -> 48.0
            - 4.26 -> 42.2
            - 4.23 -> 36.4
            - 4.21 -> 30.6
            - 4.19 -> 24.9
            - 4.16 -> 19.1
            - 4.1 -> 13.3
            - 4.07 -> 10.4
            - 4.03 -> 7.5
            - 3.97 -> 4.6
            - 3.82 -> 1.7
            - 3.27 -> 0.0
      - lambda: return clamp(x, 0.0f, 100.0f);

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO27
      mode:
        input: true
        pullup: true
    id: jack_detect
    name: Jack Detect
    internal: true
    on_press:
      - script.execute: jack_detect_high
    on_release:
      - script.execute: jack_detect_low
  - platform: gpio
    pin:
      number: GPIO19
      inverted: true
      mode:
        input: true
        pullup: true
    name: Volume Up
    on_click:
      - lambda: |-
          id(Vol) += 0.05;
          if(id(Vol) > 1) id(Vol) = 1;
      - if:
          condition:
            lambda: 'return fabsf(id(last_volume_cmd) - id(Vol)) > 0.005f;'
          then:
            - media_player.volume_set:
                id: luxe_media_player
                volume: !lambda return id(Vol);
            - lambda: id(last_volume_cmd) = id(Vol);
  - platform: gpio
    pin:
      number: GPIO32
      inverted: true
      mode:
        input: true
        pullup: true
    name: Volume Down
    on_click:
      - lambda: |-
          id(Vol) -= 0.05;
          if(id(Vol) < 0) id(Vol) = 0;
      - if:
          condition:
            lambda: 'return fabsf(id(last_volume_cmd) - id(Vol)) > 0.005f;'
          then:
            - media_player.volume_set:
                id: luxe_media_player
                volume: !lambda return id(Vol);
            - lambda: id(last_volume_cmd) = id(Vol);
  - platform: gpio
    pin:
      number: GPIO12
      inverted: true
      mode:
        input: true
        pullup: true
    name: Mute
    on_click:
      - if:
          condition:
            - lambda: 'return(id(mute));'
          then:
            - script.execute: mute_off
            - lambda: id(mute) = false;
          else:
            - script.execute: mute_on
            - lambda: id(mute) = true;
    on_double_click:
      - if:
          condition:
            - lambda: 'return(id(phase) == 2);'
          then:
            - media_player.stop:
  - platform: wifi
    name: "WLAN Status"
    id: wifi_status
    entity_category: diagnostic

text_sensor:
  - platform: template
    name: "Aktueller Titel"
    id: now_playing
    lambda: |-
      if (id(luxe_media_player).is_playing()) {
        return {"Aktueller Titel"}; // Hier den tatsächlichen Titel auslesen, falls verfügbar
      } else {
        return {"Kein Titel"};
      }
    update_interval: 1s

light:
  - platform: esp32_rmt_led_strip
    name: None
    id: top_led
    pin: GPIO22
    chipset: WS2812
    num_leds: 1
    rgb_order: grb
    default_transition_length: 0s
    gamma_correct: 2.8
    effects:
      - pulse:
          name: pulse
          transition_length: 250ms
          update_interval: 250ms
      - pulse:
          name: slow_pulse
          transition_length: 1s
          update_interval: 2s

i2s_audio:
  id: i2s0
  i2s_lrclk_pin: GPIO25
  i2s_bclk_pin: GPIO5
  i2s_mclk_pin: GPIO0

microphone:
  - platform: i2s_audio
    id: luxe_mic
    i2s_audio_id: i2s0
    sample_rate: 16000
    i2s_din_pin: GPIO35
    bits_per_sample: 16bit
    channel: stereo
    adc_type: external

speaker:
  - platform: i2s_audio
    id: luxe_speaker
    i2s_audio_id: i2s0
    i2s_dout_pin: GPIO26
    dac_type: external
    sample_rate: 48000
    bits_per_sample: 16bit
    num_channels: 2
    buffer_duration: 100ms

media_player:
  - platform: speaker
    name: None
    id: luxe_media_player
    internal: false
    announcement_pipeline:
      speaker: luxe_speaker
      format: WAV
      sample_rate: 48000
      num_channels: 1
    on_announcement:
      - micro_wake_word.stop:
      - wait_until:
          not:
            micro_wake_word.is_running:
      - microphone.mute: luxe_mic
      - lambda: |-
          id(audio_active) = true;
          id(audio_started) = false;
      - if:
          condition:
            lambda: 'return(id(phase) != 2);'
          then:
            - lambda: |-
                if(id(phase) == 1)  id(phase) = 2;
            - script.execute: mute_off
            - script.execute: update_led
    on_idle:
      - if:
          condition:
            lambda: 'return id(audio_active) && id(audio_started);'
          then:
            - wait_until:
                and:
                  - not:
                      media_player.is_announcing:
                  - not:
                      voice_assistant.is_running:
            - if:
                condition:
                  lambda: 'return((id(phase) == 4) || (id(phase) == 2));'
                then:
                  - lambda: |-
                      id(phase) = 1;
            - microphone.unmute: luxe_mic
            - micro_wake_word.start:
            - script.execute: update_led
            - lambda: |-
                id(audio_active) = false;
                id(audio_started) = false;

select:
  - platform: template
    name: "Wake word sensitivity"
    optimistic: true
    initial_option: Slightly sensitive
    restore_value: true
    entity_category: config
    options:
      - Slightly sensitive
      - Moderately sensitive
      - Very sensitive
    on_value:
      lambda: |-
        if (x == "Slightly sensitive") {
          id(okay_nabu).set_probability_cutoff(217);
          id(hey_jarvis).set_probability_cutoff(247);
          id(hey_mycroft).set_probability_cutoff(253);
        } else if (x == "Moderately sensitive") {
          id(okay_nabu).set_probability_cutoff(176);
          id(hey_jarvis).set_probability_cutoff(235);
          id(hey_mycroft).set_probability_cutoff(242);
        } else if (x == "Very sensitive") {
          id(okay_nabu).set_probability_cutoff(143);
          id(hey_jarvis).set_probability_cutoff(212);
          id(hey_mycroft).set_probability_cutoff(237);
        }

voice_assistant:
  id: va
  microphone: luxe_mic
  media_player: luxe_media_player
  micro_wake_word: mww
  use_wake_word: false
  noise_suppression_level: 2
  auto_gain: 31dBFS
  volume_multiplier: 2.0
  on_listening:
    - logger.log: "listening 3 => phase"
    - micro_wake_word.stop:
    - lambda: |-
        id(phase) = 3;
    - script.execute: update_led
  on_stt_end:
    - light.turn_on:
        id: top_led
        blue: 60%
        red: 20%
        green: 20%
        effect: pulse
  on_tts_start:
    - logger.log: "answering  4 => phase"
    - micro_wake_word.stop:
    - wait_until:
        not:
          micro_wake_word.is_running:
    - microphone.mute: luxe_mic
    - lambda: |-
        id(audio_active) = true;
        id(audio_started) = false;
    - lambda: |-
        id(phase) = 4;
    - script.execute: update_led
  on_error:
    - logger.log: "ERROR!!!!!!!!!!!!!!!!"
    - light.turn_on:
        id: top_led
        blue: 0%
        red: 100%
        green: 0%
        effect: pulse
    - delay: 3s
    - lambda: id(phase) = 1;
    - script.execute: update_led

script:
  - id: jack_detect_high
    then:
      - logger.log: "Jack detect high -> route to speaker"
      - output.turn_off: dac_mute
      - lambda: |-
          id(my_es8388).write_byte(0x1D, 0x20);
          id(my_es8388).write_byte(0x1C, 0x10);
          id(my_es8388).write_byte(0x04, 0x30);
  - id: jack_detect_low
    then:
      - logger.log: "Jack detect low -> route to line out"
      - output.turn_on: dac_mute
      - lambda: |-
          id(my_es8388).write_byte(0x1D, 0x00);
          id(my_es8388).write_byte(0x1C, 0x00);
          id(my_es8388).write_byte(0x04, 0x0C);
  - id: update_led
    then:
      - if:
          condition:
            lambda: 'return id(phase) != id(last_led_phase);'
          then:
            - lambda: id(last_led_phase) = id(phase);
            - logger.log: "==>>>update_led"
            - lambda: |-
                if(id(phase) == 0)id(start).execute();
                if(id(phase) == 1)id(waiting).execute();
                if(id(phase) == 2)id(external_player).execute();
                if(id(phase) == 3)id(listening).execute();
                if(id(phase) == 4)id(answering).execute();
  - id: start
    then:
      - light.turn_on:
          id: top_led
          effect: slow_pulse
          red: 80%
          green: 0%
          blue: 80%
      - delay: 5s
      - lambda: id(my_es8388).setup();
      - output.turn_off: dac_mute
      - lambda: id(phase) = 1;
      - micro_wake_word.stop:
      - wait_until:
          not:
            micro_wake_word.is_running:
      - microphone.mute: luxe_mic
      - delay: 200ms
      - script.execute: update_led
  - id: waiting
    then:
      - light.turn_on:
          id: top_led
          effect: none
          red: 0%
          green: 0%
          blue: 100%
          brightness: 100%
      - voice_assistant.stop:
      - micro_wake_word.start:
  - id: listening
    then:
      - light.turn_on:
          id: top_led
          effect: pulse
          red: 0%
          green: 100%
          blue: 0%
          brightness: 100%
  - id: answering
    then:
      - light.turn_on:
          id: top_led
          effect: none
          red: 0%
          green: 0%
          blue: 100%
          brightness: 100%
  - id: external_player
    then:
      - light.turn_on:
          id: top_led
          effect: none
          red: 80%
          green: 40%
          blue: 0%
  - id: mute_on
    then:
      - if:
          condition:
            lambda: 'return fabsf(id(last_volume_cmd)) > 0.005f;'
          then:
            - media_player.volume_set:
                id: luxe_media_player
                volume: '0'
            - lambda: id(last_volume_cmd) = 0.0f;
      - lambda: id(mute) = true;
  - id: mute_off
    then:
      - if:
          condition:
            lambda: 'return fabsf(id(last_volume_cmd) - id(Vol)) > 0.005f;'
          then:
            - media_player.volume_set:
                id: luxe_media_player
                volume: !lambda return(id(Vol));
            - lambda: id(last_volume_cmd) = id(Vol);
      - lambda: id(mute) = false;

Kann mir jmd weiterhelfen?

VG