I have been trying to make a small speaker with i2s and wanted to add some LED effects.
There are effects you can trigger on play, pause, idle, etc. But I wanted to display effect to “visualize” volume, when it changes.
I was not able to find anything, so I made my own with some help from folks on Discord:
esphome:
name: esp32audio1
friendly_name: Audio output 1
on_boot:
then:
- light.turn_on:
id: ledRing
red: 20%
green: 0%
blue: 0%
effect: "Slow pulse"
- media_player.volume_set:
id: player1
volume: 10%
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
on_client_connected:
- light.turn_off:
id: ledRing
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
domain: !secret domain
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Esp32Audio1 Fallback Hotspot"
password: "y74r3wv9L3sM"
captive_portal:
web_server:
port: 80
include_internal: True
log: True
local: True
version: 3
status_led:
pin:
number: GPIO15
inverted: False
media_player:
- platform: i2s_audio
name: Player 1
id: player1
dac_type: external
i2s_dout_pin: GPIO4
mode: stereo
i2s_audio_id: i2sAudio1
on_state:
- lambda:
if (id(volInternal).state != id(player1).volume) {
ESP_LOGD("volume","We have volume change from %f to %f", volInternal->state, player1->volume);
id(ledRing).turn_on().set_effect("volume bar").perform();
} else {
ESP_LOGW("volume", "Volume was not changed!");
int outState = id(player1).state;
if(outState == 2) id(ledRing).turn_on().set_effect("Walk").perform();
if(outState == 4) id(ledRing).turn_on().set_effect("TTS").perform();
if((outState != 0) && (outState != 2) && (outState != 4)) id(ledRing).turn_off().perform();
}
- delay: 2s
- lambda:
if (id(volInternal).state != id(player1).volume) {
ESP_LOGD("volume","We have END of volume change from %f to %f", volInternal->state, player1->volume);
id(volInternal).state = id(player1).volume;
int outState = id(player1).state;
if(outState == 2) id(ledRing).turn_on().set_effect("Walk").perform();
if(outState == 4) id(ledRing).turn_on().set_effect("TTS").perform();
if((outState != 2) && (outState != 4)) id(ledRing).turn_off().perform();
}
i2s_audio:
i2s_lrclk_pin: GPIO27
i2s_bclk_pin: GPIO25
id: i2sAudio1
light:
- platform: neopixelbus
type: GRB
id: ledRing
variant: ws2812
num_leds: 9
name: "LED Ring"
pin: GPIO16
default_transition_length: 0s
method:
type: esp32_rmt
channel: 0
effects:
- pulse:
name: "Slow Pulse"
transition_length: 750ms
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_color_wipe:
name: "Walk"
colors:
- red: 22%
green: 100%
blue: 100%
num_leds: 1
gradient: true
- red: 0%
green: 0%
blue: 0%
num_leds: 3
add_led_interval: 100ms
reverse: false
- addressable_color_wipe:
name: "TTS"
colors:
- red: 50%
green: 30%
blue: 0%
num_leds: 3
gradient: true
- red: 0%
green: 0%
blue: 0%
num_leds: 6
add_led_interval: 50ms
reverse: true
- addressable_lambda:
name: "volume bar"
update_interval: 100ms
lambda: |-
int volLeds = 8 * (id(player1).volume + 0.08);
// ESP_LOGD("volumeLEDS", "Current volume leds: %d", volLeds);
it.all() = Color(200, 0, 0);
it.range(0, 8 - volLeds) = Color(100, 100, 100);
button:
- platform: restart
name: "Restart device"
number:
- platform: template
name: internal volume
id: volInternal
internal: True
min_value: 0
max_value: 1
step: 0.01
initial_value: 0.5
optimistic: True
What it does is:
- when volume changes, for 2 seconds it switches the effect to volume bar. This will shine LEDs in red according current volume and the rest will shine white. After 2 seconds, the effect will reset to what it was before - even during playback
- when status is play, it will show effect Walk
- when status is announce (Text to speech is used from HA), the effect will switch to TTS