From cc15aaacbb471300c38bd4c9427251a96dd9a31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Panella?= Date: Tue, 10 Aug 2021 02:55:34 -0500 Subject: [PATCH] RFC: status_led: allow to share single light (#1974) Co-authored-by: Otto winter --- .../components/status_led/light/__init__.py | 26 +++++++ .../status_led/light/status_led_light.cpp | 68 +++++++++++++++++++ .../status_led/light/status_led_light.h | 40 +++++++++++ 3 files changed, 134 insertions(+) create mode 100644 esphome/components/status_led/light/__init__.py create mode 100644 esphome/components/status_led/light/status_led_light.cpp create mode 100644 esphome/components/status_led/light/status_led_light.h diff --git a/esphome/components/status_led/light/__init__.py b/esphome/components/status_led/light/__init__.py new file mode 100644 index 0000000000..8896046998 --- /dev/null +++ b/esphome/components/status_led/light/__init__.py @@ -0,0 +1,26 @@ +from esphome import pins +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import light +from esphome.const import CONF_OUTPUT_ID, CONF_PIN +from .. import status_led_ns + +StatusLEDLightOutput = status_led_ns.class_( + "StatusLEDLightOutput", light.LightOutput, cg.Component +) + +CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput), + cv.Required(CONF_PIN): pins.gpio_output_pin_schema, + } +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) + pin = await cg.gpio_pin_expression(config[CONF_PIN]) + cg.add(var.set_pin(pin)) + await cg.register_component(var, config) + # cg.add(cg.App.register_component(var)) + await light.register_light(var, config) diff --git a/esphome/components/status_led/light/status_led_light.cpp b/esphome/components/status_led/light/status_led_light.cpp new file mode 100644 index 0000000000..760c89f972 --- /dev/null +++ b/esphome/components/status_led/light/status_led_light.cpp @@ -0,0 +1,68 @@ +#include "status_led_light.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" + +namespace esphome { +namespace status_led { + +static const char *const TAG = "status_led"; + +void StatusLEDLightOutput::loop() { + uint32_t new_state = App.get_app_state() & STATUS_LED_MASK; + + if (new_state != this->last_app_state_) { + ESP_LOGV(TAG, "New app state 0x%08X", new_state); + } + + if ((new_state & STATUS_LED_ERROR) != 0u) { + this->pin_->digital_write(millis() % 250u < 150u); + this->last_app_state_ = new_state; + } else if ((new_state & STATUS_LED_WARNING) != 0u) { + this->pin_->digital_write(millis() % 1500u < 250u); + this->last_app_state_ = new_state; + } else if (new_state != this->last_app_state_) { + // if no error/warning -> restore light state or turn off + bool state = false; + + if (lightstate_) + lightstate_->current_values_as_binary(&state); + + this->pin_->digital_write(state); + this->last_app_state_ = new_state; + + ESP_LOGD(TAG, "Restoring light state %s", ONOFF(state)); + } +} + +void StatusLEDLightOutput::setup_state(light::LightState *state) { + lightstate_ = state; + ESP_LOGD(TAG, "'%s': Setting initital state", state->get_name().c_str()); + this->write_state(state); +} + +void StatusLEDLightOutput::write_state(light::LightState *state) { + bool binary; + state->current_values_as_binary(&binary); + + // if in warning/error, don't overwrite the status_led + // once it is back to OK, the loop will restore the state + if ((App.get_app_state() & (STATUS_LED_ERROR | STATUS_LED_WARNING)) == 0u) { + this->pin_->digital_write(binary); + ESP_LOGD(TAG, "'%s': Setting state %s", state->get_name().c_str(), ONOFF(binary)); + } +} + +void StatusLEDLightOutput::setup() { + ESP_LOGCONFIG(TAG, "Setting up Status LED..."); + + this->pin_->setup(); + this->pin_->digital_write(false); +} + +void StatusLEDLightOutput::dump_config() { + ESP_LOGCONFIG(TAG, "Status Led Light:"); + LOG_PIN(" Pin: ", this->pin_); +} + +} // namespace status_led +} // namespace esphome diff --git a/esphome/components/status_led/light/status_led_light.h b/esphome/components/status_led/light/status_led_light.h new file mode 100644 index 0000000000..8a7f4b4da8 --- /dev/null +++ b/esphome/components/status_led/light/status_led_light.h @@ -0,0 +1,40 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/esphal.h" +#include "esphome/components/light/light_output.h" + +namespace esphome { +namespace status_led { + +class StatusLEDLightOutput : public light::LightOutput, public Component { + public: + void set_pin(GPIOPin *pin) { pin_ = pin; } + + light::LightTraits get_traits() override { + auto traits = light::LightTraits(); + traits.set_supported_color_modes({light::ColorMode::ON_OFF}); + return traits; + } + + void loop() override; + + void setup_state(light::LightState *state) override; + + void write_state(light::LightState *state) override; + + void setup() override; + + void dump_config() override; + + float get_setup_priority() const override { return setup_priority::HARDWARE; } + float get_loop_priority() const override { return 50.0f; } + + protected: + GPIOPin *pin_; + light::LightState *lightstate_{}; + uint32_t last_app_state_{0xFFFF}; +}; + +} // namespace status_led +} // namespace esphome