├── hex base.stl ├── hex clip.stl ├── hex cover.stl ├── hex housing.stl ├── README.md └── hexa.yaml /hex base.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boskikak/Hexa-Voice-assistant/HEAD/hex base.stl -------------------------------------------------------------------------------- /hex clip.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boskikak/Hexa-Voice-assistant/HEAD/hex clip.stl -------------------------------------------------------------------------------- /hex cover.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boskikak/Hexa-Voice-assistant/HEAD/hex cover.stl -------------------------------------------------------------------------------- /hex housing.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boskikak/Hexa-Voice-assistant/HEAD/hex housing.stl -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hexa-Voice-assistant 2 | Voice Assistant based on ESP32 S3 N16R8 with stereo speakers and simply led clock. 3 | 4 | ## 1. Hardware: 5 | - ESP32 S3 N16R8 6 | - 2x speakers 52mm 5W 4ohm 7 | - PCM5102 8 | - PAM8406 9 | - microphone INMP411 10 | - led ring 85mm (24diodes) 11 | - buzzer 3V 12 | - speaker fabric 13 | - capacitor 1000uF 10V 14 | - usb C socket 15 | - usb C cable 16 | - 3 tact switch 6x6 h=8 17 | - 6x bolt M2.5x6 18 | - speaker fabric 19 | 20 | ## 2. Schema 21 | ![HEX](https://github.com/user-attachments/assets/d7fc0e55-0f02-47ec-b565-0f37cba82fc2) 22 | 23 | 24 | & PCM & ESP32 jumpers 25 | 26 | ![pcm](https://github.com/user-attachments/assets/1720eb65-d165-407f-b6a2-816969771dd6) 27 | ![esp jumper](https://github.com/user-attachments/assets/0e610223-f114-4200-a676-652226e11f2d) 28 | 29 | 30 | ## 3. Short description 31 | The most important settings are at the top of the code. The wake word is alexa but can be changed according to [microwakeword models](https://github.com/esphome/micro-wake-word-models/tree/main/models). The clock displays the time with an accuracy of 2.5 minutes. 32 | You can set a separate volume level for the assistant and listening time. Also you can deactivate assist and turn off clock. 33 | ![encje](https://github.com/user-attachments/assets/1a13426e-df0e-45d2-a6f0-30e610c2dd47) 34 | 35 | 36 | ## 4. Step by step 37 | ![IMG_20250608_170114694_HDR](https://github.com/user-attachments/assets/f61c8774-14b3-423d-b945-7c8f43d6437a) 38 | ![IMG_20250608_170149499_HDR](https://github.com/user-attachments/assets/12038699-115c-45fd-9ebd-e1141d13a1dd) 39 | ![IMG_20250612_101720290_HDR](https://github.com/user-attachments/assets/3df934dd-035e-4453-9cf4-878ad39db364) 40 | ![IMG_20250612_110514494_HDR](https://github.com/user-attachments/assets/8c7f466b-2a7c-419c-8564-293a3e535ba8) 41 | ![IMG_20250612_110525650_HDR](https://github.com/user-attachments/assets/f3a5a0f7-68bb-4186-adf8-f0eeee6d9596) 42 | ![IMG_20250612_111428452_HDR](https://github.com/user-attachments/assets/c09b5971-8ed2-456c-bd2e-c5a20b488a4b) 43 | 44 | 45 | ## 5. Effects 46 | ![IMG_20250608_104713100_HDR](https://github.com/user-attachments/assets/3f8e5fb1-b406-4fe7-aa1e-27d7237aaf30) 47 | ![IMG_20250509_204240465_HDR](https://github.com/user-attachments/assets/235af48c-3076-44da-9155-898e89f211a5) 48 | ![IMG_20250509_204300825_HDR](https://github.com/user-attachments/assets/85d20477-faa1-45ba-997a-93deab3a0b9d) 49 | ![IMG_20250509_204336373_HDR](https://github.com/user-attachments/assets/2da49421-44b0-4bc8-a23d-753c527bdf27) 50 | ![IMG_20250509_204452141_1](https://github.com/user-attachments/assets/7097dec2-f08d-48ca-9de9-8c2a83cad397) 51 | 52 | ## 6. Summary 53 | I recommend a 2A or 3A power supply for the speaker. Printing profiles you can find [here](https://makerworld.com/en/models/1520535-hexavoice-assistant#profileId-1593371) 54 | 55 | ## 7. What's news? 56 | 57 | 09.2025: 58 | - double click play button to unable/enable microphone 59 | - click at the same time vol+ & vol- to restart device 60 | 61 | 10.2025 62 | - stereo sounds with Esphome >2024.5 (using old libraries i2s) 63 | - choose from list your wake word and set your first choice 64 | 65 | 66 | -------------------------------------------------------------------------------- /hexa.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | friendly_name: "Hexa" 3 | leds: "24" #number of diodes in the strip 4 | waiting_time: "6s" #duration of listening assistant 5 | led_power: '40%' 6 | vol_step: "0.08" #volume step 7 | vol_start: "0.48" #starting music volume 8 | your_wake_word: "Alexa" #"Okay Nabu" or "Hey Jarvis" choose your wake word after starting speaker 9 | 10 | # PINOUT 11 | pin_buzzer: GPIO21 12 | pin_leds: GPIO38 #DI 13 | pin_lrclk_spk: GPIO7 #LCK 14 | pin_bclk_spk: GPIO5 #BCK 15 | pin_din_spk: GPIO6 #DIN 16 | pin_lrclk_mic: GPIO15 #WS 17 | pin_bclk_mic: GPIO16 #SCK 18 | pin_din_mic: GPIO17 #DIN 19 | pin_vol_up: "13" 20 | pin_vol_down: "14" 21 | pin_play: "18" 22 | 23 | esphome: 24 | name: "hexa" 25 | friendly_name: ${friendly_name} 26 | 27 | esp32: 28 | board: esp32-s3-devkitc-1 29 | cpu_frequency: 240MHz 30 | variant: esp32s3 31 | flash_size: 16MB 32 | framework: 33 | type: esp-idf 34 | version: recommended 35 | sdkconfig_options: 36 | CONFIG_ESP32S3_DATA_CACHE_64KB: "y" 37 | CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y" 38 | CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB: "y" 39 | 40 | CONFIG_SPIRAM_RODATA: "y" 41 | CONFIG_SPIRAM_FETCH_INSTRUCTIONS: "y" 42 | 43 | CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST: "y" 44 | CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY: "y" 45 | 46 | CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y" 47 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" 48 | 49 | psram: 50 | mode: octal 51 | speed: 80MHz 52 | 53 | # Enable logging 54 | logger: 55 | 56 | # Enable Home Assistant API 57 | api: 58 | encryption: 59 | key: ".........................................." 60 | on_client_connected: 61 | - script.execute: loading 62 | - delay: 1s 63 | - media_player.volume_set: !lambda return ${vol_start}; 64 | - script.execute: reset_ww 65 | - delay: 2s 66 | - switch.turn_on: led_clock 67 | - number.set: 68 | id: vol_music 69 | value: ${vol_start} 70 | 71 | ota: 72 | - platform: esphome 73 | password: "...................................." 74 | 75 | wifi: 76 | ssid: !secret wifi_ssid 77 | password: !secret wifi_password 78 | 79 | # Enable fallback hotspot (captive portal) in case wifi connection fails 80 | ap: 81 | ssid: "Hexa Fallback Hotspot" 82 | password: "................................." 83 | 84 | captive_portal: 85 | 86 | 87 | 88 | button: 89 | - platform: restart 90 | id: reboot 91 | name: "Reboot" 92 | icon: mdi:restart 93 | 94 | binary_sensor: 95 | - platform: gpio 96 | pin: 97 | number: ${pin_vol_up} 98 | mode: INPUT_PULLUP 99 | inverted: false 100 | name: "Vol+" 101 | id: vol_up 102 | internal: True 103 | on_press: 104 | if: 105 | condition: 106 | - binary_sensor.is_off: vol_down 107 | then: 108 | - button.press: reboot 109 | else: 110 | - script.stop: volume 111 | - media_player.volume_up 112 | - delay: 100ms 113 | - script.execute: volume 114 | - delay: 500ms 115 | - lambda: |- 116 | if (id(player).volume) { 117 | id(vol_music).publish_state(id(player).volume); 118 | } 119 | - platform: gpio 120 | pin: 121 | number: ${pin_vol_down} 122 | mode: INPUT_PULLUP 123 | inverted: false 124 | name: "Vol-" 125 | id: vol_down 126 | internal: True 127 | on_press: 128 | if: 129 | condition: 130 | - binary_sensor.is_off: vol_up 131 | then: 132 | - button.press: reboot 133 | else: 134 | - script.stop: volume 135 | - media_player.volume_down 136 | - delay: 100ms 137 | - script.execute: volume 138 | - delay: 500ms 139 | - lambda: |- 140 | if (id(player).volume) { 141 | id(vol_music).publish_state(id(player).volume); 142 | } 143 | - platform: gpio 144 | pin: 145 | number: ${pin_play} 146 | mode: INPUT_PULLUP 147 | inverted: false 148 | name: "Play/Pause" 149 | internal: True 150 | on_press: 151 | - media_player.toggle 152 | on_double_click: 153 | min_length: 30ms 154 | max_length: 500ms 155 | then: 156 | - script.execute: deaf 157 | 158 | 159 | switch: 160 | - platform: template 161 | id: assist 162 | icon: mdi:microphone-message 163 | name: "Assistant" 164 | optimistic: true 165 | restore_mode: RESTORE_DEFAULT_ON 166 | on_turn_on: 167 | - micro_wake_word.start 168 | on_turn_off: 169 | - micro_wake_word.stop 170 | - platform: template 171 | id: led_clock 172 | icon: mdi:clock 173 | name: "Clock" 174 | optimistic: true 175 | restore_mode: RESTORE_DEFAULT_OFF 176 | on_turn_off: 177 | - light.turn_off: ring 178 | - platform: template 179 | id: active_music 180 | name: "Active music" 181 | optimistic: true 182 | internal: True 183 | restore_mode: RESTORE_DEFAULT_OFF 184 | 185 | 186 | number: 187 | - platform: template 188 | id: vol_music 189 | optimistic: True 190 | min_value: 0 191 | max_value: 0.96 192 | step: ${vol_step} 193 | - platform: template 194 | id: vol_assist 195 | name: "Assistant volume" 196 | icon: mdi:volume-source 197 | max_value: 0.80 198 | min_value: 0.24 199 | step: ${vol_step} 200 | restore_value: True 201 | optimistic: True 202 | 203 | globals: 204 | - id: current_hour 205 | type: int 206 | restore_value: no 207 | initial_value: '0' 208 | - id: current_minute 209 | type: int 210 | restore_value: no 211 | initial_value: '0' 212 | 213 | time: 214 | - platform: sntp 215 | id: sntp_time 216 | update_interval: 10s 217 | on_time: 218 | - minutes: '*' 219 | then: 220 | - lambda: |- 221 | auto time = id(sntp_time).now(); 222 | int led_index_h = (12 + (time.hour % 12) * 2 + (time.minute >= 30 ? 1 : 0)) % 24; 223 | 224 | int led_index_m = round((time.minute * 60 + time.second) / 150.0); 225 | led_index_m = (led_index_m + 12) % 24; 226 | 227 | id(current_hour) = led_index_h; 228 | id(current_minute) = led_index_m; 229 | - if: 230 | condition: 231 | lambda: |- 232 | return id(led_clock).state == true ; 233 | then: 234 | - light.addressable_set: 235 | id: ring 236 | red: 0% 237 | green: 0% 238 | blue: 0% 239 | color_brightness: 0% 240 | - light.addressable_set: 241 | id: ring 242 | range_from: !lambda return id(current_hour); 243 | range_to: !lambda return id(current_hour); 244 | red: 100% 245 | green: 5% 246 | blue: 5% 247 | color_brightness: 60% 248 | - light.addressable_set: 249 | id: ring 250 | range_from: !lambda return id(current_minute); 251 | range_to: !lambda return id(current_minute); 252 | red: 100% 253 | green: 60% 254 | blue: 10% 255 | color_brightness: 60% 256 | 257 | 258 | output: 259 | - platform: ledc 260 | pin: ${pin_buzzer} 261 | id: rtttl_out 262 | rtttl: 263 | output: rtttl_out 264 | id: my_rtttl 265 | 266 | 267 | light: 268 | - platform: esp32_rmt_led_strip 269 | default_transition_length: 0.5s 270 | id: ring 271 | chipset: WS2812 272 | pin: ${pin_leds} 273 | num_leds: ${leds} 274 | rgb_order: GRB 275 | name: "Ring" 276 | effects: 277 | - pulse: 278 | name: "Pulse" 279 | transition_length: 200ms 280 | update_interval: 230ms 281 | min_brightness: 15% 282 | max_brightness: ${led_power} 283 | - addressable_color_wipe: 284 | name: "Detecting" 285 | colors: 286 | - red: 10% 287 | green: 100% 288 | blue: 100% 289 | num_leds: 7 290 | gradient: false 291 | - red: 0% 292 | green: 0% 293 | blue: 0% 294 | num_leds: 19 295 | add_led_interval: 30ms 296 | reverse: true 297 | - addressable_color_wipe: 298 | name: "Loading" 299 | colors: 300 | - red: 10% 301 | green: 100% 302 | blue: 100% 303 | num_leds: 24 304 | gradient: false 305 | - red: 0% 306 | green: 0% 307 | blue: 0% 308 | num_leds: 1 309 | add_led_interval: 125ms 310 | reverse: False 311 | 312 | 313 | i2s_audio: 314 | - id: i2s_output 315 | i2s_lrclk_pin: ${pin_lrclk_spk} 316 | i2s_bclk_pin: ${pin_bclk_spk} 317 | use_legacy: true #uses old library but stereo music works 318 | - id: i2s_input 319 | i2s_lrclk_pin: ${pin_lrclk_mic} 320 | i2s_bclk_pin: ${pin_bclk_mic} 321 | use_legacy: true 322 | 323 | 324 | micro_wake_word: 325 | id: mww 326 | models: 327 | - model: alexa 328 | id: alexa 329 | probability_cutoff: 0.5 330 | sliding_window_size: 2 331 | - model: https://github.com/kahrendt/microWakeWord/releases/download/okay_nabu_20241226.3/okay_nabu.json 332 | id: okay_nabu 333 | - model: hey_jarvis 334 | id: hey_jarvis 335 | vad: 336 | microphone: mic 337 | on_wake_word_detected: 338 | if: 339 | condition: 340 | - media_player.is_playing: 341 | then: 342 | - logger.log: "S T O P M U S I C" 343 | - switch.turn_on: active_music 344 | - delay: 100ms 345 | - switch.turn_off: led_clock 346 | - script.stop: detecting 347 | - delay: 100ms 348 | - media_player.pause 349 | - voice_assistant.start: 350 | wake_word: !lambda return wake_word; 351 | - script.execute: detecting 352 | - delay: 50ms 353 | - rtttl.play: 'two_short:d=4,o=5,b=100:16e6,16e6' 354 | else: 355 | - switch.turn_off: active_music 356 | - switch.turn_off: led_clock 357 | - delay: 100ms 358 | - script.stop: detecting 359 | - delay: 200ms 360 | - voice_assistant.start: 361 | wake_word: !lambda return wake_word; 362 | - script.execute: detecting 363 | - delay: 50ms 364 | - rtttl.play: 'two_short:d=4,o=5,b=100:16e6,16e6' 365 | 366 | 367 | voice_assistant: 368 | id: va 369 | microphone: mic 370 | media_player: player 371 | use_wake_word: false 372 | noise_suppression_level: 0 373 | volume_multiplier: 1 374 | auto_gain: 0dBFS 375 | on_error: 376 | - delay: 100ms 377 | - script.execute: reset_ww 378 | - script.execute: error 379 | - script.stop: detecting 380 | on_tts_start: 381 | - switch.turn_off: led_clock 382 | - script.stop: detecting 383 | - media_player.volume_set: !lambda return id(vol_assist).state; 384 | - delay: 100ms 385 | - script.execute: speaking 386 | on_start: 387 | - logger.log: "M I C R O P H O N E S T A R T" 388 | on_end: 389 | if: 390 | condition: 391 | - switch.is_on: active_music 392 | then: 393 | - light.turn_off: ring 394 | - switch.turn_off: led_clock 395 | - script.execute: reset_ww 396 | - wait_until: 397 | condition: 398 | not: 399 | media_player.is_announcing: 400 | - delay: 1s 401 | - media_player.play 402 | - logger.log: "E N D A S S I S T A N T P L A Y M U S I C" 403 | else: 404 | - light.turn_off: ring 405 | - switch.turn_off: led_clock 406 | - delay: 200ms 407 | - script.execute: reset_ww 408 | - logger.log: "E N D A S S I S T A N T W I T H O U T M U S I C" 409 | 410 | 411 | media_player: 412 | - platform: speaker 413 | id: player 414 | name: "Speaker" 415 | internal: False 416 | icon: mdi:dots-hexagon 417 | task_stack_in_psram: true 418 | volume_increment: ${vol_step} 419 | volume_min: 0.0 420 | volume_max: 0.96 421 | media_pipeline: 422 | speaker: media_spk_resampling_input 423 | format: FLAC # FLAC is the least processor intensive codec 424 | num_channels: 2 425 | sample_rate: 48000 426 | announcement_pipeline: 427 | speaker: announcement_spk_resampling_input 428 | format: FLAC # FLAC is the least processor intensive codec 429 | num_channels: 1 # Stereo audio is unnecessary for announcements 430 | sample_rate: 48000 431 | on_state: 432 | then: 433 | if: 434 | condition: 435 | and: 436 | - media_player.is_announcing: 437 | - not: 438 | voice_assistant.is_running 439 | then: 440 | - logger.log: "S T A R T T T S" 441 | - switch.turn_off: led_clock 442 | - delay: 500ms 443 | - script.execute: speaking 444 | - delay: 1s 445 | - wait_until: 446 | condition: 447 | not: 448 | media_player.is_announcing: 449 | - script.execute: reset_ww 450 | - light.turn_off: ring 451 | - media_player.volume_set: !lambda return (id(vol_music).state); 452 | - logger.log: "E N D T T S" 453 | - delay: 4s 454 | - switch.turn_on: led_clock 455 | else: 456 | if: 457 | condition: 458 | - media_player.is_announcing: 459 | then: 460 | - logger.log: "S T A R T A S S I S T" 461 | - wait_until: 462 | condition: 463 | not: 464 | media_player.is_announcing: 465 | - logger.log: "E N D A S S I S T" 466 | - script.execute: reset_ww 467 | - light.turn_off: ring 468 | - media_player.volume_set: !lambda return (id(vol_music).state); 469 | - delay: 4s 470 | - switch.turn_on: led_clock 471 | 472 | 473 | speaker: 474 | - platform: i2s_audio 475 | id: i2s_audio_speaker 476 | sample_rate: 48000 477 | i2s_mode: primary 478 | i2s_dout_pin: ${pin_din_spk} 479 | bits_per_sample: 32bit 480 | i2s_audio_id: i2s_output 481 | dac_type: external 482 | channel: stereo 483 | timeout: never 484 | buffer_duration: 100ms 485 | - platform: mixer 486 | id: mixer_speaker_id 487 | output_speaker: i2s_audio_speaker 488 | source_speakers: 489 | - id: announcement_spk_mixer_input 490 | - id: media_spk_mixer_input 491 | - platform: resampler 492 | id: media_spk_resampling_input 493 | output_speaker: media_spk_mixer_input 494 | - platform: resampler 495 | id: announcement_spk_resampling_input 496 | output_speaker: announcement_spk_mixer_input 497 | 498 | 499 | microphone: 500 | - platform: i2s_audio 501 | id: mic 502 | adc_type: external 503 | i2s_din_pin: ${pin_din_mic} 504 | channel: left 505 | i2s_audio_id: i2s_input 506 | 507 | 508 | select: 509 | - platform: template 510 | name: "Wake word" 511 | optimistic: true 512 | initial_option: ${your_wake_word} 513 | icon: mdi:microphone 514 | restore_value: true 515 | entity_category: config 516 | options: 517 | - Alexa 518 | - Okay Nabu 519 | - Hey Jarvis 520 | on_value: 521 | if: 522 | condition: 523 | lambda: 'return x == "Alexa";' 524 | then: 525 | - micro_wake_word.enable_model: alexa 526 | - micro_wake_word.disable_model: okay_nabu 527 | - micro_wake_word.disable_model: hey_jarvis 528 | else: 529 | if: 530 | condition: 531 | lambda: 'return x == "Okay Nabu";' 532 | then: 533 | - micro_wake_word.enable_model: okay_nabu 534 | - micro_wake_word.disable_model: alexa 535 | - micro_wake_word.disable_model: hey_jarvis 536 | else: 537 | if: 538 | condition: 539 | lambda: 'return x == "Hey Jarvis";' 540 | then: 541 | - micro_wake_word.enable_model: hey_jarvis 542 | - micro_wake_word.disable_model: alexa 543 | - micro_wake_word.disable_model: okay_nabu 544 | 545 | script: 546 | - id: reset_ww 547 | then: 548 | - micro_wake_word.stop 549 | - delay: 250ms 550 | - micro_wake_word.start 551 | - id: detecting 552 | then: 553 | - switch.turn_off: led_clock 554 | - delay: 250ms 555 | - light.turn_on: 556 | id: ring 557 | red: 20% 558 | green: 80% 559 | blue: 100% 560 | brightness: ${led_power} 561 | effect: Detecting 562 | - delay: ${waiting_time} 563 | - voice_assistant.stop 564 | - light.turn_off: ring 565 | - script.execute: reset_ww 566 | - delay: 5s 567 | - switch.turn_on: led_clock 568 | - id: loading 569 | then: 570 | - switch.turn_off: led_clock 571 | - delay: 250ms 572 | - light.turn_on: 573 | id: ring 574 | red: 20% 575 | green: 80% 576 | blue: 100% 577 | brightness: ${led_power} 578 | effect: loading 579 | - delay: 3s 580 | - light.turn_off: ring 581 | - delay: 2s 582 | - switch.turn_on: led_clock 583 | - id: speaking 584 | then: 585 | - light.turn_on: 586 | id: ring 587 | red: 0% 588 | green: 100% 589 | blue: 0% 590 | brightness: ${led_power} 591 | effect: Pulse 592 | - id: error 593 | then: 594 | - switch.turn_off: led_clock 595 | - delay: 250ms 596 | - light.turn_on: 597 | id: ring 598 | red: 100% 599 | green: 0% 600 | blue: 0% 601 | brightness: ${led_power} 602 | effect: none 603 | - delay: 3s 604 | - light.turn_off: ring 605 | - delay: 1s 606 | - switch.turn_on: led_clock 607 | - id: volume 608 | then: 609 | - switch.turn_off: led_clock 610 | - light.turn_off: ring 611 | - delay: 150ms 612 | - light.addressable_set: 613 | id: ring 614 | range_from: 0 615 | range_to: !lambda return round(id(player).volume * 25); 616 | red: 25% 617 | green: 25% 618 | blue: 100% 619 | - delay: 1s 620 | - light.turn_off: ring 621 | - delay: 5s 622 | - switch.turn_on: led_clock 623 | - id: deaf 624 | then: 625 | if: 626 | condition: 627 | - switch.is_on: assist 628 | then: 629 | - switch.turn_off: led_clock 630 | - delay: 250ms 631 | - light.turn_on: 632 | id: ring 633 | red: 100% 634 | green: 0% 635 | blue: 0% 636 | brightness: ${led_power} 637 | - switch.toggle: assist 638 | - delay: 1s 639 | - light.turn_off: ring 640 | - delay: 1s 641 | - switch.turn_on: led_clock 642 | else: 643 | - switch.turn_off: led_clock 644 | - delay: 250ms 645 | - light.turn_on: 646 | id: ring 647 | red: 0% 648 | green: 100% 649 | blue: 0% 650 | brightness: ${led_power} 651 | - switch.toggle: assist 652 | - delay: 1s 653 | - light.turn_off: ring 654 | - delay: 1s 655 | - switch.turn_on: led_clock 656 | --------------------------------------------------------------------------------