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