Skip to content

Instantly share code, notes, and snippets.

@tetele
Last active May 7, 2024 00:15
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • 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
@jperquin
Copy link

Hi there. Many thanks for this yaml-config!

After installing a direct copy of the above today 17 may 23, I am getting the following log output. Looks like something gets stuck on setting up the media player..

INFO Updating https://github.com/esphome/esphome.git@pull/3552/head
INFO Updating https://github.com/esphome/esphome.git@pull/4775/head
WARNING GPIO12 is a Strapping PIN and should be avoided.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Starting log output from muse-luxe.local using esphome API
INFO Successfully connected to muse-luxe.local
[08:35:18][I][app:102]: ESPHome version 2023.5.0 compiled on May 17 2023, 08:32:21
[08:35:18][C][wifi:505]: WiFi:
[08:35:18][C][wifi:363]:   Local MAC: 94:B5:55:38:33:34
[08:35:18][C][wifi:364]:   SSID: 'LvO-P22'[redacted]
[08:35:18][C][wifi:365]:   IP Address: 192.168.1.82
[08:35:18][C][wifi:367]:   BSSID: 60:22:32:49:D9:DD[redacted]
[08:35:18][C][wifi:368]:   Hostname: 'muse-luxe'
[08:35:18][C][wifi:370]:   Signal strength: -68 dB ▂▄▆█
[08:35:18][C][wifi:374]:   Channel: 11
[08:35:18][C][wifi:375]:   Subnet: 255.255.255.0
[08:35:18][C][wifi:376]:   Gateway: 192.168.1.1
[08:35:18][C][wifi:377]:   DNS1: 192.168.1.1
[08:35:18][C][wifi:378]:   DNS2: 0.0.0.0
[08:35:18][C][logger:301]: Logger:
[08:35:18][C][logger:302]:   Level: DEBUG
[08:35:18][C][logger:303]:   Log Baud Rate: 115200
[08:35:18][C][logger:305]:   Hardware UART: UART0
[08:35:18][C][i2c.arduino:053]: I2C Bus:
[08:35:18][C][i2c.arduino:054]:   SDA Pin: GPIO18
[08:35:18][C][i2c.arduino:055]:   SCL Pin: GPIO23
[08:35:18][C][i2c.arduino:056]:   Frequency: 50000 Hz
[08:35:18][C][i2c.arduino:059]:   Recovery: bus successfully recovered
[08:35:18][I][i2c.arduino:069]: Results from i2c bus scan:
[08:35:18][I][i2c.arduino:075]: Found i2c device at address 0x10
[08:35:18][C][gpio.output:010]: GPIO Binary Output:
[08:35:18][C][gpio.output:011]:   Pin: GPIO21
[08:35:18][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Middle button'
[08:35:18][C][gpio.binary_sensor:016]:   Pin: GPIO12
[08:35:18][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Volume Up'
[08:35:18][C][gpio.binary_sensor:016]:   Pin: GPIO19
[08:35:18][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Volume Down'
[08:35:18][C][gpio.binary_sensor:016]:   Pin: GPIO32
[08:35:18][C][light:103]: Light 'led'
[08:35:18][C][light:105]:   Default Transition Length: 0.0s
[08:35:18][C][light:106]:   Gamma Correct: 2.80
[08:35:18][C][adc:087]: ADC Sensor 'Battery'
[08:35:18][C][adc:087]:   Device Class: 'voltage'
[08:35:18][C][adc:087]:   State Class: 'measurement'
[08:35:18][C][adc:087]:   Unit of Measurement: 'V'
[08:35:18][C][adc:087]:   Accuracy Decimals: 3
[08:35:18][C][adc:087]:   Icon: 'mdi:battery-outline'
[08:35:18][C][adc:097]:   Pin: GPIO33
[08:35:18][C][adc:112]:  Attenuation: 11db
[08:35:18][C][adc:126]:   Update Interval: 15.0s
[08:35:18][C][captive_portal:088]: Captive Portal:
[08:35:18][C][mdns:108]: mDNS:
[08:35:18][C][mdns:109]:   Hostname: muse-luxe
[08:35:18][C][ota:093]: Over-The-Air Updates:
[08:35:18][C][ota:094]:   Address: muse-luxe.local:3232
[08:35:18][C][api:138]: API Server:
[08:35:18][C][api:139]:   Address: muse-luxe.local:6053
[08:35:18][C][api:143]:   Using noise encryption: NO
[08:35:18][C][improv_serial:032]: Improv Serial:
[08:35:18][C][audio:190]: Audio:

@tetele
Copy link
Author

tetele commented May 17, 2023

I haven't tried ESPHome 2023.5 yet, I'll get back with an update after I do.

@tetele
Copy link
Author

tetele commented May 18, 2023

@jperquin OK, So I've installed ESPHome 2023.5.1 and it looks like it works ok. It's not "stuck", that's just the last thing it needs to do before connecting to HA (if you've set it up like that).

[09:28:13][I][app:102]: ESPHome version 2023.5.1 compiled on May 18 2023, 09:27:21
[09:28:13][C][wifi:505]: WiFi:
[09:28:13][C][wifi:363]:   Local MAC: XX:XX:XX:XX:XX:XX
[09:28:13][C][wifi:364]:   SSID: [redacted]
[09:28:13][C][wifi:365]:   IP Address: 10.17.30.243
[09:28:13][C][wifi:367]:   BSSID: [redacted]
[09:28:13][C][wifi:368]:   Hostname: 'muse-luxe'
[09:28:13][C][wifi:370]:   Signal strength: -48 dB ▂▄▆█
[09:28:13][C][wifi:374]:   Channel: 1
[09:28:13][C][wifi:375]:   Subnet: 255.240.0.0
[09:28:13][C][wifi:376]:   Gateway: 10.16.0.1
[09:28:13][C][wifi:377]:   DNS1: 10.16.8.3
[09:28:13][C][wifi:378]:   DNS2: 0.0.0.0
[09:28:13][C][logger:301]: Logger:
[09:28:13][C][logger:302]:   Level: DEBUG
[09:28:13][C][logger:303]:   Log Baud Rate: 115200
[09:28:13][C][logger:305]:   Hardware UART: UART0
[09:28:13][C][i2c.arduino:053]: I2C Bus:
[09:28:13][C][i2c.arduino:054]:   SDA Pin: GPIO18
[09:28:13][C][i2c.arduino:055]:   SCL Pin: GPIO23
[09:28:13][C][i2c.arduino:056]:   Frequency: 50000 Hz
[09:28:13][C][i2c.arduino:059]:   Recovery: bus successfully recovered
[09:28:13][I][i2c.arduino:069]: Results from i2c bus scan:
[09:28:13][I][i2c.arduino:075]: Found i2c device at address 0x10
[09:28:13][C][gpio.output:010]: GPIO Binary Output:
[09:28:13][C][gpio.output:011]:   Pin: GPIO21
[09:28:13][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Middle button'
[09:28:13][C][gpio.binary_sensor:016]:   Pin: GPIO12
[09:28:13][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Volume Up'
[09:28:13][C][gpio.binary_sensor:016]:   Pin: GPIO19
[09:28:13][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Volume Down'
[09:28:13][C][gpio.binary_sensor:016]:   Pin: GPIO32
[09:28:13][D][light:035]: 'led' Setting:
[09:28:13][D][light:046]:   State: OFF
[09:28:13][D][light:108]:   Effect: 'None'
[09:28:13][C][light:103]: Light 'led'
[09:28:13][C][light:105]:   Default Transition Length: 0.0s
[09:28:13][C][light:106]:   Gamma Correct: 2.80
[09:28:13][C][adc:087]: ADC Sensor 'Battery'
[09:28:13][C][adc:087]:   Device Class: 'voltage'
[09:28:13][C][adc:087]:   State Class: 'measurement'
[09:28:13][C][adc:087]:   Unit of Measurement: 'V'
[09:28:13][C][adc:087]:   Accuracy Decimals: 3
[09:28:13][C][adc:087]:   Icon: 'mdi:battery-outline'
[09:28:13][C][adc:097]:   Pin: GPIO33
[09:28:13][C][adc:112]:  Attenuation: 11db
[09:28:13][C][adc:126]:   Update Interval: 15.0s
[09:28:13][C][captive_portal:088]: Captive Portal:
[09:28:13][C][mdns:108]: mDNS:
[09:28:13][C][mdns:109]:   Hostname: muse-luxe
[09:28:13][C][ota:093]: Over-The-Air Updates:
[09:28:13][C][ota:094]:   Address: muse-luxe.local:3232
[09:28:13][C][api:138]: API Server:
[09:28:13][C][api:139]:   Address: muse-luxe.local:6053
[09:28:13][C][api:141]:   Using noise encryption: YES
[09:28:14][C][improv_serial:032]: Improv Serial:
[09:28:14][C][audio:190]: Audio:
[09:28:15][D][api:102]: Accepted 10.16.8.1
[09:28:15][D][api.connection:959]: Home Assistant 2023.5.3 (10.16.8.1): Connected successfully

I have tried the new speaker component but it doesn't seem to work OK yet.

@erikpendragon
Copy link

are your volume up and own working?
I can't seem to get them to work.
[16:22:04][D][binary_sensor:036]: 'Volume Down': Sending state ON
[16:22:04][D][binary_sensor:036]: 'Volume Down': Sending state OFF
[16:22:04][D][media_player:059]: 'TV Room Muse Luxe d53778' - Setting
[16:22:04][D][media_player:063]: Command: UNKNOWN

@tetele
Copy link
Author

tetele commented Jul 17, 2023

@erikpendragon sorry for the delay, I was on vacation. They work only while media (i.e. a response) is playing.

@jplivingston08
Copy link

I copied and installed your code/config above. Installed fine. When trying to use the button to listen and send a command, I get the below using both home assistant cloud and home assistant local.
[E][voice_assistant:231]: Error: stt-stream-failed - speech-to-text failed
Any ideas?

@tetele
Copy link
Author

tetele commented Jul 19, 2023

@jplivingston08 what STT engine do you use on the default voice assistant in HA? And what version of HA?

@jplivingston08
Copy link

I have both HA Cloud and Whisper. Tried both with the same result. HA is 2023.7.0

@tetele
Copy link
Author

tetele commented Jul 19, 2023

Is the ESPHome device allowed to make service calls in HA?

Screenshot_20230719_213108_Home Assistant

@jplivingston08
Copy link

It was not. I just enabled but still seems to timeout waiting for speech. I will keep playing with it this weekend to see if I can figure it out. nice work !

@Zagur
Copy link

Zagur commented Aug 11, 2023

It doesn't work for me.

When validating the yaml it gives me the following error:

Failed config
media_player.i2s_audio: [source /config/esphome/.esphome/packages/7b8574f6/raspiaudio-muse-luxe.yaml:51]
  
Too many candidates found for 'i2s_audio_id' type 'i2s_audio::I2SAudioComponent' You must assign an explicit ID to the parent component you want to use.

Do I have to change something in the configuration?

@tetele
Copy link
Author

tetele commented Aug 11, 2023

What version of ESPHome are you running @Zagur ?

@Zagur
Copy link

Zagur commented Aug 11, 2023

@tetele The latest version available: 2023.7.1. Only works with 2013.5?

@tetele
Copy link
Author

tetele commented Aug 14, 2023

@Zagur sorry for the delay, I was out for a few days. I've tried reproducing your error and I can't. Are you sure you haven't defined multiple other I2S audio devices that are not present in the config in this gist? Could you share your full config and an updated error message?

@Zagur
Copy link

Zagur commented Aug 14, 2023

@tetele I just tried again and this time it worked correctly. I don't know exactly what it was leaving me the other time, but it's finally working! Thank you very much!

@sbach89
Copy link

sbach89 commented Dec 19, 2023

First, I want to say thank you, this is awesome.

Second, what's going on with the voltages here for the battery? That Reddit post is correct, an 18650 100% is 4.2V and 0% is 3v.

Finally, is this able to stream audio? (Music, notifications, etc.) The Music Assistant add-on doesn't recognize it, and using the Media section in HA will not play anything.

@drache42
Copy link

@tetele A couple of questions for you.

Is this still required with my speaker running ESPHome 2023.11 and HA 2024.1?
If it is required, then I'm getting issues with the !lambda return x; in the yaml file. HA doesn't seem to know what that means.

@tomlut
Copy link

tomlut commented Feb 8, 2024

You should be able to remove this from the readme now:

Known issues and limitations

the media_player component in ESPHome home-assistant/core#92969. It works with cloud STT, though

The link to the issue shows it has been resolved.

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