#pragma once #include "esphome/core/component.h" #include "esphome/components/fan/fan.h" #include "ap2_hub.h" namespace esphome { namespace ap2_hub { /* Per-slot fan: off + speeds 1..4 -> gear A0..A4. Commands are silently dropped * while the slot is not ready (unset / disconnected / scanning). */ class AP2Fan : public fan::Fan, public Component { public: void set_hub(AP2Hub *hub) { this->hub_ = hub; } void set_slot(uint8_t slot) { this->slot_ = slot; } fan::FanTraits get_traits() override { auto t = fan::FanTraits(); t.set_speed(true); t.set_supported_speed_count(4); return t; } /* Reflect the AP2's actual gear (from an M9033 poll) into this entity WITHOUT * sending a command back — keeps the UI in sync with the physical button. */ void update_from_device(uint8_t gear) { bool st = gear > 0; int sp = gear > 0 ? (int) gear : this->speed; if (this->state == st && (!st || this->speed == sp)) return; // no change this->state = st; if (st) this->speed = sp; this->publish_state(); } protected: void control(const fan::FanCall &call) override; AP2Hub *hub_{nullptr}; uint8_t slot_{0}; }; } // namespace ap2_hub } // namespace esphome