--- substitutions: name: pyramid1 friendly_name: Pyramid 1 # Casita images loading_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/casita/loading_320_240.png idle_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/casita/idle_320_240.png listening_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/casita/listening_320_240.png thinking_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/casita/thinking_320_240.png replying_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/casita/replying_320_240.png error_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/casita/error_320_240.png error_no_wifi_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/error_box_illustrations/error-no-wifi.png error_no_ha_illustration_file: https://github.com/esphome/wake-word-voice-assistants/raw/main/error_box_illustrations/error-no-ha.png # Fonts mdi_webfont_file: https://raw.githubusercontent.com/Templarian/MaterialDesign-Webfont/master/fonts/materialdesignicons-webfont.ttf # Audio files wake_word_trigger_sound_file: wake_word_triggered.wav # timer_finished_sound_file: https://github.com/esphome/home-assistant-voice-pe/raw/dev/sounds/timer_finished.flac # error_cloud_expired_file: https://github.com/esphome/home-assistant-voice-pe/raw/dev/sounds/error_cloud_expired.mp3 # Micro wake word models pick_pig: https://raw.githubusercontent.com/esphome/micro-wake-word-models/refs/heads/main/models/v2/experiments/hey_peppa_pig.json stop_model_file: https://github.com/kahrendt/microWakeWord/releases/download/stop/stop.json # Background colors loading_illustration_background_color: "000000" idle_illustration_background_color: "000000" listening_illustration_background_color: "FFFFFF" thinking_illustration_background_color: "FFFFFF" replying_illustration_background_color: "FFFFFF" error_illustration_background_color: "000000" # Phases of the Voice Assistant # The voice assistant is ready to be triggered by a wake word voice_assist_idle_phase_id: "1" # The voice assistant is listening for a voice command voice_assist_listening_phase_id: "2" # The voice assistant is currently processing the command voice_assist_thinking_phase_id: "3" # The voice assistant is replying to the command voice_assist_replying_phase_id: "4" # The voice assistant is not ready voice_assist_not_ready_phase_id: "10" # The voice assistant encountered an error voice_assist_error_phase_id: "11" # Muted phase voice_assist_muted_phase_id: "12" # Finished timer phase voice_assist_timer_finished_phase_id: "20" esphome: name: pyramid1 friendly_name: Pyramid 1 min_version: 2025.11.3 on_boot: priority: 600 then: - delay: 30s - if: condition: lambda: return id(init_in_progress); then: - lambda: id(init_in_progress) = false; esp32: variant: esp32s3 flash_size: 8MB cpu_frequency: 240MHz framework: type: esp-idf api: encryption: key: "innoIL7I6ZfRekL58F65REjeYNLW1Hp/Q/Kv9SEjnNA=" ota: - platform: esphome password: "22de00dcf5c2701a25d2fe719d596123" wifi: ssid: !secret wifi_ssid password: !secret wifi_password ap: ssid: "Echo-Pyramid Fallback Hotspot" password: "uSTvJjVzweZp" # Enable logging logger: level: INFO logs: sensor: WARN captive_portal: button: - platform: factory_reset id: factory_reset_btn internal: true binary_sensor: - platform: gpio pin: number: GPIO41 mode: INPUT_PULLUP inverted: true id: user_button internal: true on_multi_click: - timing: - ON for at least 50ms - OFF for at least 50ms then: - switch.turn_off: timer_ringing - timing: - ON for at least 10s then: - button.press: factory_reset_btn external_components: - source: github://m5stack/esphome-yaml/components components: [aw87559, si5351, lp5562, pyramidrgb, pyramidtouch] refresh: 0s # I2C Bus Configuration i2c: - id: bsp_bus sda: GPIO45 scl: GPIO0 scan: true - id: ext_bus # used on atomic echo base sda: GPIO38 scl: GPIO39 # Ehco Base GPIO Expander pi4ioe5v6408: - id: pi4ioe5v6408_hub i2c_id: ext_bus address: 0x43 aw87559: id: audio_amp i2c_id: ext_bus address: 0x5B si5351: id: clock_gen i2c_id: ext_bus address: 0x60 # I2S Bus Configuration i2s_audio: - id: i2s_audio_bus i2s_lrclk_pin: GPIO8 i2s_bclk_pin: GPIO6 spi: clk_pin: GPIO15 mosi_pin: GPIO21 # miso_pin is not used audio_dac: - platform: es8311 id: es8311_dac i2c_id: ext_bus bits_per_sample: 16bit sample_rate: 16000 audio_adc: - platform: es7210 id: es7210_adc i2c_id: ext_bus address: 0x40 bits_per_sample: 16bit sample_rate: 16000 microphone: - platform: i2s_audio id: i2s_mic sample_rate: 16000 i2s_din_pin: GPIO5 bits_per_sample: 16bit adc_type: external channel: stereo speaker: - platform: i2s_audio id: i2s_speaker i2s_dout_pin: GPIO7 dac_type: external bits_per_sample: 16bit sample_rate: 16000 channel: mono audio_dac: es8311_dac media_player: - platform: speaker name: "Echo Pyramid Player" id: echo_pyramid_player volume_min: 0.0 volume_max: 1.0 volume_initial: 0.10 buffer_size: 6000 announcement_pipeline: speaker: i2s_speaker format: WAV # sample_rate: 48000 # num_channels: 1 codec_support_enabled: false files: - id: wake_word_triggered_sound file: ${wake_word_trigger_sound_file} # - id: timer_finished_sound # file: ${timer_finished_sound_file} # - id: error_cloud_expired # file: ${error_cloud_expired_file} on_state: - logger.log: "State updated!" on_play: - logger.log: "Playback started!" on_announcement: - logger.log: "Announcing!" # Stop the wake word (mWW or VA) if the mic is capturing - if: condition: - microphone.is_capturing: then: - script.execute: stop_wake_word # Ensure VA stops before moving on - if: condition: - lambda: |- return id(wake_word_engine_location).current_option() == "In Home Assistant"; then: - wait_until: - not: voice_assistant.is_running: # Since VA isn't running, this is user-intiated media playback. Draw the mute display - if: condition: not: voice_assistant.is_running: then: - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id}; - script.execute: draw_display on_idle: # Since VA isn't running, this is the end of user-intiated media playback. Restart the wake word. - if: condition: not: voice_assistant.is_running: then: - script.execute: start_wake_word - script.execute: set_idle_or_mute_phase - script.execute: draw_display switch: # NS4150B - platform: gpio name: Speaker Enable pin: pi4ioe5v6408: pi4ioe5v6408_hub number: 0 mode: output: true icon: "mdi:volume-high" restore_mode: RESTORE_DEFAULT_ON - platform: template name: Mute Microphone id: mute icon: "mdi:microphone-off" optimistic: true restore_mode: RESTORE_DEFAULT_OFF entity_category: config on_turn_off: - microphone.unmute: - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id}; on_turn_on: - microphone.mute: - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id}; - platform: template id: timer_ringing optimistic: true internal: true restore_mode: ALWAYS_OFF on_turn_off: # Turn off the repeat mode and disable the pause between playlist items - lambda: |- id(echo_pyramid_player) ->make_call() .set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_OFF) .set_announcement(true) .perform(); id(echo_pyramid_player)->set_playlist_delay_ms(speaker::AudioPipelineType::ANNOUNCEMENT, 0); # Stop playing the alarm - media_player.stop: announcement: true - script.execute: start_wake_word on_turn_on: - script.execute: stop_wake_word # Turn on the repeat mode and pause for 1000 ms between playlist items/repeats - lambda: |- id(echo_pyramid_player) ->make_call() .set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ONE) .set_announcement(true) .perform(); id(echo_pyramid_player)->set_playlist_delay_ms(speaker::AudioPipelineType::ANNOUNCEMENT, 1000); # - media_player.speaker.play_on_device_media_file: # media_file: timer_finished_sound # announcement: true - delay: 15min - switch.turn_off: timer_ringing select: - platform: template entity_category: config name: Wake word engine location id: wake_word_engine_location icon: "mdi:account-voice" optimistic: true restore_value: true options: - In Home Assistant - On device initial_option: On device on_value: - if: condition: lambda: return !id(init_in_progress); then: - wait_until: lambda: return id(voice_assistant_phase) == ${voice_assist_muted_phase_id} || id(voice_assistant_phase) == ${voice_assist_idle_phase_id}; - if: condition: lambda: return x == "In Home Assistant"; then: - micro_wake_word.stop - delay: 500ms - if: condition: switch.is_off: mute then: - lambda: id(va).set_use_wake_word(true); - voice_assistant.start_continuous: - if: condition: lambda: return x == "On device"; then: - lambda: id(va).set_use_wake_word(false); - voice_assistant.stop - delay: 500ms - if: condition: switch.is_off: mute then: - micro_wake_word.start - 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: # Sets specific wake word probabilities computed for each particular model # Note probability cutoffs are set as a quantized uint8 value, each comment has the corresponding floating point cutoff # False Accepts per Hour values are tested against all units and channels from the Dinner Party Corpus. # These cutoffs apply only to the specific models included in the firmware: okay_nabu@20241226.3, hey_jarvis@v2, hey_mycroft@v2 lambda: |- if (x == "Slightly sensitive") { id(okay_nabu).set_probability_cutoff(217); // 0.85 -> 0.000 FAPH on DipCo (Manifest's default) id(hey_jarvis).set_probability_cutoff(247); // 0.97 -> 0.563 FAPH on DipCo (Manifest's default) id(hey_mycroft).set_probability_cutoff(253); // 0.99 -> 0.567 FAPH on DipCo } else if (x == "Moderately sensitive") { id(okay_nabu).set_probability_cutoff(176); // 0.69 -> 0.376 FAPH on DipCo id(hey_jarvis).set_probability_cutoff(235); // 0.92 -> 0.939 FAPH on DipCo id(hey_mycroft).set_probability_cutoff(242); // 0.95 -> 1.502 FAPH on DipCo (Manifest's default) } else if (x == "Very sensitive") { id(okay_nabu).set_probability_cutoff(143); // 0.56 -> 0.751 FAPH on DipCo id(hey_jarvis).set_probability_cutoff(212); // 0.83 -> 1.502 FAPH on DipCo id(hey_mycroft).set_probability_cutoff(237); // 0.93 -> 1.878 FAPH on DipCo } micro_wake_word: id: mww microphone: i2s_mic models: - model: okay_nabu id: okay_nabu - model: hey_jarvis id: hey_jarvis - model: hey_mycroft id: hey_mycroft - model: https://raw.githubusercontent.com/esphome/micro-wake-word-models/refs/heads/main/models/v2/experiments/hey_peppa_pig.json id: hey_peppa_pig - model: ${stop_model_file} id: stop internal: true vad: on_wake_word_detected: - script.execute: id: play_sound priority: true sound_file: !lambda return id(wake_word_triggered_sound); - wait_until: condition: - media_player.is_announcing: timeout: 0.5s # Announcement is finished and the I2S bus is free - wait_until: - and: - not: media_player.is_announcing: - not: speaker.is_playing: - voice_assistant.start: wake_word: !lambda return wake_word; voice_assistant: id: va microphone: i2s_mic media_player: echo_pyramid_player micro_wake_word: mww noise_suppression_level: 2 auto_gain: 31dBFS volume_multiplier: 2.0 on_listening: - lambda: id(voice_assistant_phase) = ${voice_assist_listening_phase_id}; - script.execute: draw_display on_stt_vad_end: - lambda: id(voice_assistant_phase) = ${voice_assist_thinking_phase_id}; - script.execute: draw_display on_tts_start: - lambda: id(voice_assistant_phase) = ${voice_assist_replying_phase_id}; - script.execute: draw_display on_end: # Wait a short amount of time to see if an announcement starts - wait_until: condition: - media_player.is_announcing: timeout: 0.5s # Announcement is finished and the I2S bus is free - wait_until: - and: - not: media_player.is_announcing: - not: speaker.is_playing: # Restart only mWW if enabled; streaming wake words automatically restart - if: condition: - lambda: |- return id(wake_word_engine_location).current_option() == "On device"; then: - lambda: id(va).set_use_wake_word(false); - micro_wake_word.start: - script.execute: set_idle_or_mute_phase - script.execute: draw_display on_error: # Only set the error phase if the error code is different than duplicate_wake_up_detected or stt-no-text-recognized # These two are ignored for a better user experience - if: condition: and: - lambda: return !id(init_in_progress); - lambda: return code != "duplicate_wake_up_detected"; - lambda: return code != "stt-no-text-recognized"; then: - lambda: id(voice_assistant_phase) = ${voice_assist_error_phase_id}; - script.execute: draw_display - delay: 1s - if: condition: switch.is_off: mute then: - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id}; else: - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id}; # If the error code is cloud-auth-failed, serve a local audio file guiding the user. - if: condition: - lambda: return code == "cloud-auth-failed"; then: # - script.execute: # id: play_sound # priority: true # sound_file: !lambda return id(error_cloud_expired); - script.execute: draw_display on_client_connected: - lambda: id(init_in_progress) = false; - script.execute: start_wake_word - script.execute: set_idle_or_mute_phase - script.execute: draw_display on_client_disconnected: - script.execute: stop_wake_word - lambda: id(voice_assistant_phase) = ${voice_assist_not_ready_phase_id}; - script.execute: draw_display on_timer_finished: - switch.turn_on: timer_ringing - wait_until: media_player.is_announcing: - lambda: id(voice_assistant_phase) = ${voice_assist_timer_finished_phase_id}; globals: - id: init_in_progress type: bool restore_value: false initial_value: "true" - id: voice_assistant_phase type: int restore_value: false initial_value: ${voice_assist_not_ready_phase_id} - id: current_volume type: float restore_value: true initial_value: "0.3" sensor: - platform: pyramidtouch address: 0x1A i2c_id: ext_bus update_interval: 50ms publish_swipe_event: true swipe_timeout_ms: 500 touch1: name: "Touch 1" touch2: name: "Touch 2" touch3: name: "Touch 3" touch4: name: "Touch 4" swipe_event: name: "Touch Swipe Event" entity_category: diagnostic on_value: then: - lambda: |- // Swipe codes: // 1 = Left Up (volume up) // 2 = Left Down (volume down) // 3 = Right Up (brightness up) // 4 = Right Down (brightness down) const float volume_step = 0.05f; // 5% volume per gesture const float brightness_step = 5.0f; // 5% brightness per gesture const int ev = (int) x; if (ev == 1 || ev == 2) { // Left side: control volume (0.0 - 1.0) float v = id(current_volume); if (ev == 1) { v = std::min(1.0f, v + volume_step); } else { v = std::max(0.0f, v - volume_step); } auto call = id(echo_pyramid_player).make_call(); call.set_volume(v); call.perform(); id(current_volume) = v; } else if (ev == 3 || ev == 4) { // Right side: control RGB brightness (0 - 100) float b = id(rgb_master_brightness).state; if (ev == 3) { b = std::min(100.0f, b + brightness_step); } else { b = std::max(0.0f, b - brightness_step); } uint8_t b8 = (uint8_t) b; id(pyramid_rgb1).set_strip_brightness(1, b8); id(pyramid_rgb2).set_strip_brightness(2, b8); id(rgb_master_brightness).publish_state(b); } else { return; } lp5562: id: lp5562_led i2c_id: bsp_bus use_internal_clk: true # power_save_mode: true # high_pwm_freq: true # logarithmic_dimming: true white_current: 17.5 pyramidrgb: - id: pyramid_rgb1 i2c_id: ext_bus address: 0x1A strip: 1 brightness: 80 - id: pyramid_rgb2 i2c_id: ext_bus address: 0x1A strip: 2 brightness: 80 number: # Master media player volume (0.0–1.0) - platform: template name: "Master Volume" id: master_volume icon: "mdi:volume-high" min_value: 0.0 max_value: 0.4 step: 0.01 restore_value: true initial_value: 0.3 optimistic: true set_action: - lambda: |- float v = x; auto call = id(echo_pyramid_player).make_call(); call.set_volume(v); call.perform(); id(current_volume) = v; # Master RGB brightness (applies to both strips, 0–100%) - platform: template name: "RGB Master Brightness" id: rgb_master_brightness icon: "mdi:brightness-6" min_value: 0 max_value: 100 step: 1 restore_value: true initial_value: 100 optimistic: true set_action: - lambda: |- uint8_t b = (uint8_t) x; id(pyramid_rgb1).set_strip_brightness(1, b); id(pyramid_rgb2).set_strip_brightness(2, b); output: - platform: lp5562 id: lp5562_white_channel lp5562_id: lp5562_led channel: white - platform: pyramidrgb id: rgb1_ch0_red pyramidrgb_id: pyramid_rgb1 channel: 0 color: red - platform: pyramidrgb id: rgb1_ch0_green pyramidrgb_id: pyramid_rgb1 channel: 0 color: green - platform: pyramidrgb id: rgb1_ch0_blue pyramidrgb_id: pyramid_rgb1 channel: 0 color: blue # Strip 1, Channel 1 (Group 2) - platform: pyramidrgb id: rgb1_ch1_red pyramidrgb_id: pyramid_rgb1 channel: 1 color: red - platform: pyramidrgb id: rgb1_ch1_green pyramidrgb_id: pyramid_rgb1 channel: 1 color: green - platform: pyramidrgb id: rgb1_ch1_blue pyramidrgb_id: pyramid_rgb1 channel: 1 color: blue # Strip 2, Channel 2 (Group 1) - platform: pyramidrgb id: rgb2_ch2_red pyramidrgb_id: pyramid_rgb2 channel: 2 color: red - platform: pyramidrgb id: rgb2_ch2_green pyramidrgb_id: pyramid_rgb2 channel: 2 color: green - platform: pyramidrgb id: rgb2_ch2_blue pyramidrgb_id: pyramid_rgb2 channel: 2 color: blue # Strip 2, Channel 3 (Group 2) - platform: pyramidrgb id: rgb2_ch3_red pyramidrgb_id: pyramid_rgb2 channel: 3 color: red - platform: pyramidrgb id: rgb2_ch3_green pyramidrgb_id: pyramid_rgb2 channel: 3 color: green - platform: pyramidrgb id: rgb2_ch3_blue pyramidrgb_id: pyramid_rgb2 channel: 3 color: blue light: - platform: monochromatic name: "LCD Backlight" output: lp5562_white_channel icon: "mdi:television" restore_mode: RESTORE_DEFAULT_ON - platform: rgb name: "Strip1 Group1" red: rgb1_ch0_red green: rgb1_ch0_green blue: rgb1_ch0_blue restore_mode: RESTORE_DEFAULT_ON - platform: rgb name: "Strip1 Group2" red: rgb1_ch1_red green: rgb1_ch1_green blue: rgb1_ch1_blue restore_mode: RESTORE_DEFAULT_ON - platform: rgb name: "Strip2 Group1" red: rgb2_ch2_red green: rgb2_ch2_green blue: rgb2_ch2_blue restore_mode: RESTORE_DEFAULT_ON - platform: rgb name: "Strip2 Group2" red: rgb2_ch3_red green: rgb2_ch3_green blue: rgb2_ch3_blue restore_mode: RESTORE_DEFAULT_ON display: - platform: mipi_spi id: atoms3r_lcd model: ST7789V dc_pin: GPIO42 reset_pin: GPIO48 cs_pin: GPIO14 data_rate: 40MHz dimensions: height: 128 width: 128 offset_width: 2 offset_height: 1 invert_colors: true rotation: 180° pages: - id: idle_page lambda: |- it.fill(id(idle_color)); it.image((it.get_width() / 2), (it.get_height() / 2), id(casita_idle), ImageAlign::CENTER); - id: listening_page lambda: |- it.fill(id(listening_color)); it.image((it.get_width() / 2), (it.get_height() / 2), id(casita_listening), ImageAlign::CENTER); - id: thinking_page lambda: |- it.fill(id(thinking_color)); it.image((it.get_width() / 2), (it.get_height() / 2), id(casita_thinking), ImageAlign::CENTER); - id: replying_page lambda: |- it.fill(id(replying_color)); it.image((it.get_width() / 2), (it.get_height() / 2), id(casita_replying), ImageAlign::CENTER); - id: error_page lambda: |- it.fill(id(error_color)); it.image((it.get_width() / 2), (it.get_height() / 2), id(casita_error), ImageAlign::CENTER); - id: no_ha_page lambda: |- it.image((it.get_width() / 2), (it.get_height() / 2), id(error_no_ha), ImageAlign::CENTER); - id: no_wifi_page lambda: |- it.image((it.get_width() / 2), (it.get_height() / 2), id(error_no_wifi), ImageAlign::CENTER); - id: initializing_page lambda: |- it.fill(id(loading_color)); it.image((it.get_width() / 2), (it.get_height() / 2), id(casita_initializing), ImageAlign::CENTER); - id: muted_page lambda: |- it.fill(Color::BLACK); it.printf(0, 0, id(mdi_icon_128), Color::WHITE, "%s", "\U000F036D"); script: # Starts either mWW or the streaming wake word, depending on the configured location - id: start_wake_word then: - if: condition: and: - not: - voice_assistant.is_running: - lambda: |- return id(wake_word_engine_location).current_option() == "On device"; then: - lambda: id(va).set_use_wake_word(false); - micro_wake_word.start: - if: condition: and: - not: - voice_assistant.is_running: - lambda: |- return id(wake_word_engine_location).current_option() == "In Home Assistant"; then: - lambda: id(va).set_use_wake_word(true); - voice_assistant.start_continuous: # Stops either mWW or the streaming wake word, depending on the configured location - id: stop_wake_word then: - if: condition: lambda: |- return id(wake_word_engine_location).current_option() == "In Home Assistant"; then: - lambda: id(va).set_use_wake_word(false); - voice_assistant.stop: - if: condition: lambda: |- return id(wake_word_engine_location).current_option() == "On device"; then: - micro_wake_word.stop: # Set the voice assistant phase to idle or muted, depending on if the software mute switch is activated - id: set_idle_or_mute_phase then: - if: condition: switch.is_off: mute then: - lambda: id(voice_assistant_phase) = ${voice_assist_idle_phase_id}; else: - lambda: id(voice_assistant_phase) = ${voice_assist_muted_phase_id}; - id: play_sound parameters: priority: bool sound_file: "audio::AudioFile*" then: - lambda: |- if (priority) { id(echo_pyramid_player) ->make_call() .set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_STOP) .set_announcement(true) .perform(); } if ( (id(echo_pyramid_player).state != media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING ) || priority) { id(echo_pyramid_player) ->play_file(sound_file, true, false); } - id: draw_display then: - if: condition: lambda: return !id(init_in_progress); then: - if: condition: wifi.connected: then: - if: condition: api.connected: then: - lambda: | switch(id(voice_assistant_phase)) { case ${voice_assist_listening_phase_id}: id(atoms3r_lcd).show_page(listening_page); id(atoms3r_lcd).update(); break; case ${voice_assist_thinking_phase_id}: id(atoms3r_lcd).show_page(thinking_page); id(atoms3r_lcd).update(); break; case ${voice_assist_replying_phase_id}: id(atoms3r_lcd).show_page(replying_page); id(atoms3r_lcd).update(); break; case ${voice_assist_error_phase_id}: id(atoms3r_lcd).show_page(error_page); id(atoms3r_lcd).update(); break; case ${voice_assist_muted_phase_id}: id(atoms3r_lcd).show_page(muted_page); id(atoms3r_lcd).update(); break; case ${voice_assist_not_ready_phase_id}: id(atoms3r_lcd).show_page(no_ha_page); id(atoms3r_lcd).update(); break; default: id(atoms3r_lcd).show_page(idle_page); id(atoms3r_lcd).update(); } else: - display.page.show: no_ha_page - component.update: atoms3r_lcd else: - display.page.show: no_wifi_page - component.update: atoms3r_lcd else: - display.page.show: initializing_page - component.update: atoms3r_lcd image: - file: ${error_illustration_file} id: casita_error resize: 160x120 type: RGB transparency: alpha_channel - file: ${idle_illustration_file} id: casita_idle resize: 160x120 type: RGB transparency: alpha_channel - file: ${listening_illustration_file} id: casita_listening resize: 160x120 type: RGB transparency: alpha_channel - file: ${thinking_illustration_file} id: casita_thinking resize: 160x120 type: RGB transparency: alpha_channel - file: ${replying_illustration_file} id: casita_replying resize: 160x120 type: RGB transparency: alpha_channel - file: ${loading_illustration_file} id: casita_initializing resize: 160x120 type: RGB transparency: alpha_channel - file: ${error_no_wifi_illustration_file} id: error_no_wifi resize: 160x120 type: RGB transparency: alpha_channel - file: ${error_no_ha_illustration_file} id: error_no_ha resize: 160x120 type: RGB transparency: alpha_channel font: - file: ${mdi_webfont_file} id: mdi_icon_128 size: 128 bpp: 4 glyphs: - "\U000F036D" # mdi:mic-mute color: - id: idle_color hex: ${idle_illustration_background_color} - id: listening_color hex: ${listening_illustration_background_color} - id: thinking_color hex: ${thinking_illustration_background_color} - id: replying_color hex: ${replying_illustration_background_color} - id: loading_color hex: ${loading_illustration_background_color} - id: error_color hex: ${error_illustration_background_color}