--- # Status on a visible RGB light, which stays a normal light otherwise: # network down red, slow blink # no API client (HA) orange, slow blink # OTA blue, fast blink; green when done, 3 red blinks on error # back to normal green for 1 s, then the light goes back to how it was # packages: # status_led: !include # file: common/status_led.yaml # vars: # light_id: led_light # Needs the ota id ota_esphome (common/ota_esp32.yaml). defaults: brightness: "0.3" globals: - id: status_led_active type: bool initial_value: "false" - id: status_led_saved type: light::LightColorValues - id: status_led_last type: uint32_t initial_value: "0xFFFFFFFF" script: - id: status_led_show parameters: r: float g: float b: float lit: bool then: - lambda: |- auto *l = id(${light_id}); uint32_t key = (lit << 24) | (uint32_t(r * 255) << 16) | (uint32_t(g * 255) << 8) | uint32_t(b * 255); if (!id(status_led_active)) { id(status_led_saved) = l->remote_values; id(status_led_active) = true; } else if (key == id(status_led_last)) { return; // unchanged: don't flood Home Assistant with the same state } id(status_led_last) = key; if (lit) { l->turn_on().set_rgb(r, g, b).set_brightness(${brightness}).set_transition_length(0).set_effect("None").perform(); } else { l->turn_off().set_transition_length(0).perform(); } l->loop(); // write now: OTA blocks the main loop - id: status_led_restore parameters: confirm: bool then: - lambda: |- if (id(status_led_active) && confirm) id(status_led_show)->execute(0.0f, 1.0f, 0.0f, true); - if: condition: lambda: 'return id(status_led_active) && confirm;' then: - delay: 1s # green: back to normal - lambda: |- if (!id(status_led_active)) return; id(status_led_active) = false; id(status_led_last) = 0xFFFFFFFF; id(${light_id})->make_call().from_light_color_values(id(status_led_saved)).set_transition_length(0).perform(); interval: - interval: 500ms then: - lambda: |- static uint8_t tick = 0; tick++; bool slow = (tick / 2) % 2 == 0; // 1 s on, 1 s off bool problem = !network::is_connected() || !api::global_api_server->is_connected(); if (problem) id(status_led_restore)->stop(); if (!network::is_connected()) { id(status_led_show)->execute(1.0f, 0.0f, 0.0f, slow); } else if (!api::global_api_server->is_connected()) { id(status_led_show)->execute(1.0f, 0.4f, 0.0f, slow); } else if (id(status_led_active) && !id(status_led_restore)->is_running()) { id(status_led_restore)->execute(true); } ota: - id: !extend ota_esphome on_begin: - script.execute: id: status_led_show r: 0.0 g: 0.0 b: 1.0 lit: true on_progress: - lambda: 'id(status_led_show)->execute(0.0f, 0.0f, 1.0f, (millis() / 250) % 2 == 0);' on_end: - script.execute: id: status_led_show r: 0.0 g: 1.0 b: 0.0 lit: true on_error: - repeat: count: 3 then: - script.execute: id: status_led_show r: 1.0 g: 0.0 b: 0.0 lit: true - delay: 250ms - script.execute: id: status_led_show r: 1.0 g: 0.0 b: 0.0 lit: false - delay: 250ms - script.execute: id: status_led_restore confirm: false