Skip to content

Instantly share code, notes, and snippets.

@tetele
Last active February 27, 2025 09:48
Show Gist options
  • Save tetele/5cac735174527c3b373b10db8d9c8d77 to your computer and use it in GitHub Desktop.
Save tetele/5cac735174527c3b373b10db8d9c8d77 to your computer and use it in GitHub Desktop.
ESPHome config - Raspiaudio Muse Luxe as a voice assistant satellite in Home Assistant

Introduction

The purpose of this ESPHome config is to be able to use the Raspiaudio Muse Luxe as a voice assistant satellite in Home Assistant.

Features

  • wake word, push to talk and continuous conversation support
  • response playback
  • service exposed in HA to start and stop the voice assistant from another device/trigger
  • visual feedback of the recording/success/error status via the Luxe's onboard LED

Pre-requisites

  • Home Assistant 2023.10.0 or newer
  • A voice assistant configured in HA with STT and TTS in a language of your choice
  • ESPHome 2023.10.1 or newer

Known issues and limitations

Installation instructions

If the Muse Luxe has already been added to ESPHome

Edit your config and paste the one below. Double check Wifi connection details, API encryption key and device name/friendly name to make sure you use your own.

If the Muse Luxe is not already in ESPHome

Add a new ESP32 device in ESPHome, using the configuration below.

After the device has been added to ESPHome

Compile and install the firmware on the speaker. If auto discovery is turned on, the device should appear in Home Assistant automatically. Otherwise, check out this guide.

Credits

GithubSponsor or BuyMeCoffee

substitutions:
name: "muse-luxe"
friendly_name: "RaspiAudio Muse Luxe"
wifi_ap_password: ""
esphome:
name: ${name}
friendly_name: ${friendly_name}
name_add_mac_suffix: false
min_version: 2023.10.1
on_boot:
then:
- output.turn_on: dac_mute
- light.turn_on:
id: top_led
effect: slow_pulse
red: 100%
green: 60%
blue: 0%
esp32:
board: esp-wrover-kit
framework:
type: arduino
logger:
api:
services:
- service: start_va
then:
- voice_assistant.start
- service: stop_va
then:
- voice_assistant.stop
ota:
i2c:
sda: GPIO18
scl: GPIO23
wifi:
ap:
password: "${wifi_ap_password}"
captive_portal:
improv_serial:
external_components:
- source: github://RASPIAUDIO/esphomeLuxe@main
components: [es8388]
refresh: 0s
es8388:
globals:
- id: wifi_connected
type: bool
initial_value: "false"
restore_value: false
interval:
- interval: 1s
then:
- if:
condition:
and:
- lambda: "return !id(wifi_connected);"
- wifi.connected:
then:
- globals.set:
id: wifi_connected
value: "true"
- light.turn_on:
id: top_led
effect: pulse
red: 0%
green: 100%
blue: 0%
- delay: 1s
- light.turn_off: top_led
output:
- platform: gpio
id: dac_mute
pin: GPIO21
inverted: true
i2s_audio:
- i2s_lrclk_pin: GPIO25
i2s_bclk_pin: GPIO5
media_player:
- platform: i2s_audio
name: None
id: luxe_out
dac_type: external
i2s_dout_pin: GPIO26
mode: stereo
on_state:
if:
condition:
media_player.is_playing:
then:
output.turn_off: dac_mute
else:
output.turn_on: dac_mute
microphone:
- platform: i2s_audio
id: luxe_microphone
i2s_din_pin: GPIO35
adc_type: external
pdm: false
voice_assistant:
id: va
microphone: luxe_microphone
media_player: luxe_out
use_wake_word: true
on_listening:
- light.turn_on:
id: top_led
blue: 100%
red: 0%
green: 0%
brightness: 100%
effect: pulse
on_tts_start:
- light.turn_on:
id: top_led
blue: 60%
red: 20%
green: 20%
effect: none
on_tts_end:
- media_player.play_media: !lambda return x;
- light.turn_on:
id: top_led
blue: 60%
red: 20%
green: 20%
effect: pulse
# This is useful when you want to stream the response on another media_player
# - homeassistant.service:
# service: media_player.play_media
# data:
# entity_id: media_player.some_speaker
# media_content_id: !lambda 'return x;'
# media_content_type: music
# announce: "true"
on_client_connected:
- if:
condition:
- switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
on_client_disconnected:
- if:
condition:
- switch.is_on: use_wake_word
then:
- voice_assistant.stop:
on_end:
- delay: 100ms
- wait_until:
not:
media_player.is_playing: luxe_out
- script.execute: reset_led
on_error:
- light.turn_on:
id: top_led
blue: 0%
red: 100%
green: 0%
effect: none
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- lambda: |-
if (code == "wake-provider-missing" || code == "wake-engine-missing") {
id(use_wake_word).turn_off();
}
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 # https://forum.raspiaudio.com/t/esp-muse-luxe-bluetooth-speaker/294/12
- 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: GPIO19
inverted: true
mode:
input: true
pullup: true
name: Volume Up
on_click:
- media_player.volume_up: luxe_out
- platform: gpio
pin:
number: GPIO32
inverted: true
mode:
input: true
pullup: true
name: Volume Down
on_click:
- media_player.volume_down: luxe_out
- platform: gpio
pin:
number: GPIO12
inverted: true
mode:
input: true
pullup: true
name: Action
on_click:
- if:
condition:
switch.is_off: use_wake_word
then:
- if:
condition: voice_assistant.is_running
then:
- voice_assistant.stop:
- script.execute: reset_led
else:
- voice_assistant.start:
else:
- voice_assistant.stop
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- voice_assistant.start_continuous:
light:
- platform: esp32_rmt_led_strip
name: None
id: top_led
pin: GPIO22
chipset: SK6812
num_leds: 1
rgb_order: grb
rmt_channel: 0
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
script:
- id: reset_led
then:
- if:
condition:
switch.is_on: use_wake_word
then:
- light.turn_on:
id: top_led
blue: 100%
red: 100%
green: 0%
brightness: 100%
effect: none
else:
- light.turn_off: top_led
switch:
- platform: template
name: Use Wake Word
id: use_wake_word
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
on_turn_on:
- lambda: id(va).set_use_wake_word(true);
- if:
condition:
not:
- voice_assistant.is_running
then:
- voice_assistant.start_continuous
- script.execute: reset_led
on_turn_off:
- voice_assistant.stop
- lambda: id(va).set_use_wake_word(false);
- script.execute: reset_led
@jf1452
Copy link

jf1452 commented Jan 3, 2025

Hi, thanks for responding. I'm using a PI5 running HAOS, the ESP device is the raspiaudio Muse.

@SvenPaterson
Copy link

@SvenPaterson no, timers are not included. The config is a little outdated, to be fair 😅

I appreciate your response. Unfortunately I had no luck with this yaml nor the “official” firmware at raspiaudio.github.com, nor the esphome projects page. I’ve come across a few different versions of yaml for voice assistant implementation of this hardware but they all either not installed properly / had issues at compile or exhibited poor performance (ie consistent wake word recognition or perform ain’t appropriate actions after receding a command) I’ve had to just fall back on using this as a squeezelite box and forget the VA functionality entirely for now. Seems a shame. Maybe someone better at esp programming will figure it out! Of course, could always just be my incorrect config in the end 🤣

@mguellsegarra
Copy link

mguellsegarra commented Jan 20, 2025

I’ve noticed multiple discussions on Reddit and other forums where users have reported very low volume levels with the ESP Muse Luxe when using ESPHome.

I’m experiencing a similar issue—my ESP Muse Luxe outputs noticeably low volume when running ESPHome firmware. Despite experimenting with various YAML configurations, I haven’t been able to achieve full volume. Interestingly, with my custom Arduino sketch (muse-mqtt-audioplayer), the speaker outputs at maximum volume.

I tried to troubleshoot, so I attempted to modify the register values in the ESPHome ES8388 component (PR #3552) to align with those in the RASPIAUDIO Muse library (museS3.cpp), but this approach hasn’t yielded any improvements.

In my sketch, I utilize the ESP32-audioI2S library by @schreibfaul1. I noticed that ESPHome uses its own fork of this library, esphome/ESP32-audioI2S.

I tried too the new PR #6956 but volume problem persists.

Has anyone else faced similar issues with the ESP Muse Luxe and ESPHome? Any insights or suggestions would be greatly appreciated. Tagging @jesserockz, @tetele and @RASPIAUDIO for their expertise. Thank you all for your great work!

@tetele
Copy link
Author

tetele commented Jan 20, 2025

@mguellsegarra you can try esphome/esphome#6956 (which supersedes https://github.com/esphome/esphome/pull/3552/files#diff-8a184938984a60dadf629e018497ded60f1eed994e3173ff1b9bf1dca360207c). I haven't used my Luxe in a long time, so I don't know if this config still works with newer versions of ESPHome.

@mguellsegarra
Copy link

@mguellsegarra you can try esphome/esphome#6956 (which supersedes github.com/esphome/esphome/pull/3552/files#diff-8a184938984a60dadf629e018497ded60f1eed994e3173ff1b9bf1dca360207c). I haven't used my Luxe in a long time, so I don't know if this config still works with newer versions of ESPHome.

It works, but it does not fix the volume thing. Thanks four your reply :)

@RASPIAUDIO
Copy link

RASPIAUDIO commented Jan 20, 2025

Hi I have just updated the component here :
https://github.com/RASPIAUDIO/esphomeLuxe/blob/main/components/es8388/es8388_component.cpp

at the end :

  //fully differential output Left -L1/R1
  this->write_byte(0x2E, 0x21);
  this->write_byte(0x2F, 0x21);

    //fully differential output Right -L2/R2
  this->write_byte(0x30, 0x21);
  this->write_byte(0x31, 0x21);

if you use this yaml it will call this component
https://github.com/RASPIAUDIO/esphomeLuxe/blob/main/raspiaudio-muse-luxe.yaml

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

I think I hear a difference in volume but if someone could confirm?

edit: I do hear a difference

@mguellsegarra
Copy link

@RASPIAUDIO, thanks for your response and the modifications! I tried something similar without success—it’s clear who really knows their stuff here, haha. I think I was missing setting the 0x21 value to the 0x30 and 0x31 registers. I’ll test out your suggestions and share my results here. 🎉

@mgottholsen
Copy link

Hi I have just updated the component here : https://github.com/RASPIAUDIO/esphomeLuxe/blob/main/components/es8388/es8388_component.cpp

at the end :

  //fully differential output Left -L1/R1
  this->write_byte(0x2E, 0x21);
  this->write_byte(0x2F, 0x21);

    //fully differential output Right -L2/R2
  this->write_byte(0x30, 0x21);
  this->write_byte(0x31, 0x21);

if you use this yaml it will call this component https://github.com/RASPIAUDIO/esphomeLuxe/blob/main/raspiaudio-muse-luxe.yaml

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

I think I hear a difference in volume but if someone could confirm?

edit: I do hear a difference

I can confirm, I hear a difference with this most recent change.

@drasch
Copy link

drasch commented Feb 22, 2025

I had to change these lines:

    on_click:
      - media_player.volume_up: luxe_out

to:

    on_click:
      - media_player.volume_up: 
          id: luxe_out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment