#pragma once #include "esphome/core/component.h" #include "esphome/core/automation.h" #include "esphome/core/helpers.h" #include "esphome/core/preferences.h" #include "esphome/components/output/float_output.h" namespace esphome { namespace servo { extern uint32_t global_servo_id; class Servo : public Component { public: void set_output(output::FloatOutput *output) { output_ = output; } void write(float value) { value = clamp(value, -1.0f, 1.0f); float level; if (value < 0.0) level = lerp(-value, this->idle_level_, this->min_level_); else level = lerp(value, this->idle_level_, this->max_level_); this->output_->set_level(level); this->save_level_(level); } void detach() { this->output_->set_level(0.0f); this->save_level_(0.0f); } void setup() override { float v; if (this->restore_) { this->rtc_ = global_preferences.make_preference(global_servo_id); global_servo_id++; if (this->rtc_.load(&v)) { this->output_->set_level(v); return; } } this->detach(); } void dump_config() override; float get_setup_priority() const override { return setup_priority::DATA; } void set_min_level(float min_level) { min_level_ = min_level; } void set_idle_level(float idle_level) { idle_level_ = idle_level; } void set_max_level(float max_level) { max_level_ = max_level; } void set_restore(bool restore) { restore_ = restore; } protected: void save_level_(float v) { this->rtc_.save(&v); } output::FloatOutput *output_; float min_level_ = 0.0300f; float idle_level_ = 0.0750f; float max_level_ = 0.1200f; bool restore_{false}; ESPPreferenceObject rtc_; }; template class ServoWriteAction : public Action { public: ServoWriteAction(Servo *servo) : servo_(servo) {} TEMPLATABLE_VALUE(float, value) void play(Ts... x) override { this->servo_->write(this->value_.value(x...)); } protected: Servo *servo_; }; template class ServoDetachAction : public Action { public: ServoDetachAction(Servo *servo) : servo_(servo) {} void play(Ts... x) override { this->servo_->detach(); } protected: Servo *servo_; }; } // namespace servo } // namespace esphome