#pragma once // WARNING: This component is EXPERIMENTAL. The API may change at any time // without following the normal breaking changes policy. Use at your own risk. // Once the API is considered stable, this warning will be removed. #include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/components/remote_base/remote_base.h" #include namespace esphome::infrared { /// Capability flags for individual infrared instances enum InfraredCapability : uint32_t { CAPABILITY_TRANSMITTER = 1 << 0, // Can transmit signals CAPABILITY_RECEIVER = 1 << 1, // Can receive signals }; /// Forward declarations class Infrared; /// InfraredCall - Builder pattern for transmitting infrared signals class InfraredCall { public: explicit InfraredCall(Infrared *parent) : parent_(parent) {} /// Set the carrier frequency in Hz InfraredCall &set_carrier_frequency(uint32_t frequency); // ===== Raw Timings Methods ===== // All set_raw_timings_* methods store pointers/references to external data. // The referenced data must remain valid until perform() completes. // Safe pattern: call.set_raw_timings_xxx(data); call.perform(); // synchronous // Unsafe pattern: call.set_raw_timings_xxx(data); defer([call]() { call.perform(); }); // data may be gone! /// Set the raw timings from a vector (positive = mark, negative = space) /// @note Lifetime: Stores a pointer to the vector. The vector must outlive perform(). /// @note Usage: Primarily for lambdas/automations where the vector is in scope. InfraredCall &set_raw_timings(const std::vector &timings); /// Set the raw timings from base64url-encoded little-endian int32 data /// @note Lifetime: Stores a pointer to the string. The string must outlive perform(). /// @note Usage: For web_server - base64url is fully URL-safe (uses '-' and '_'). /// @note Decoding happens at perform() time, directly into the transmit buffer. InfraredCall &set_raw_timings_base64url(const std::string &base64url); /// Set the raw timings from packed protobuf sint32 data (zigzag + varint encoded) /// @note Lifetime: Stores a pointer to the buffer. The buffer must outlive perform(). /// @note Usage: For API component where data comes directly from the protobuf message. InfraredCall &set_raw_timings_packed(const uint8_t *data, uint16_t length, uint16_t count); /// Set the number of times to repeat transmission (1 = transmit once, 2 = transmit twice, etc.) InfraredCall &set_repeat_count(uint32_t count); /// Perform the transmission void perform(); /// Get the carrier frequency const optional &get_carrier_frequency() const { return this->carrier_frequency_; } /// Get the raw timings (only valid if set via set_raw_timings) const std::vector &get_raw_timings() const { return *this->raw_timings_; } /// Check if raw timings have been set (any format) bool has_raw_timings() const { return this->raw_timings_ != nullptr || this->packed_data_ != nullptr || this->base64url_ptr_ != nullptr; } /// Check if using packed data format bool is_packed() const { return this->packed_data_ != nullptr; } /// Check if using base64url data format bool is_base64url() const { return this->base64url_ptr_ != nullptr; } /// Get the base64url data string const std::string &get_base64url_data() const { return *this->base64url_ptr_; } /// Get packed data (only valid if set via set_raw_timings_packed) const uint8_t *get_packed_data() const { return this->packed_data_; } uint16_t get_packed_length() const { return this->packed_length_; } uint16_t get_packed_count() const { return this->packed_count_; } /// Get the repeat count uint32_t get_repeat_count() const { return this->repeat_count_; } protected: uint32_t repeat_count_{1}; Infrared *parent_; optional carrier_frequency_; // Pointer to vector-based timings (caller-owned, must outlive perform()) const std::vector *raw_timings_{nullptr}; // Pointer to base64url-encoded string (caller-owned, must outlive perform()) const std::string *base64url_ptr_{nullptr}; // Pointer to packed protobuf buffer (caller-owned, must outlive perform()) const uint8_t *packed_data_{nullptr}; uint16_t packed_length_{0}; uint16_t packed_count_{0}; }; /// InfraredTraits - Describes the capabilities of an infrared implementation class InfraredTraits { public: bool get_supports_transmitter() const { return this->supports_transmitter_; } void set_supports_transmitter(bool supports) { this->supports_transmitter_ = supports; } bool get_supports_receiver() const { return this->supports_receiver_; } void set_supports_receiver(bool supports) { this->supports_receiver_ = supports; } uint32_t get_receiver_frequency_hz() const { return this->receiver_frequency_hz_; } void set_receiver_frequency_hz(uint32_t freq) { this->receiver_frequency_hz_ = freq; } protected: bool supports_transmitter_{false}; bool supports_receiver_{false}; uint32_t receiver_frequency_hz_{0}; // Demodulation frequency of the IR receiver in Hz (0 = unspecified) }; /// Infrared - Base class for infrared remote control implementations class Infrared : public Component, public EntityBase, public remote_base::RemoteReceiverListener { public: Infrared() = default; void setup() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; } /// Set the remote receiver component void set_receiver(remote_base::RemoteReceiverBase *receiver) { this->receiver_ = receiver; } /// Set the remote transmitter component void set_transmitter(remote_base::RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; } /// Check if this infrared has a transmitter configured bool has_transmitter() const { return this->transmitter_ != nullptr; } /// Check if this infrared has a receiver configured bool has_receiver() const { return this->receiver_ != nullptr; } /// Get the traits for this infrared implementation InfraredTraits &get_traits() { return this->traits_; } const InfraredTraits &get_traits() const { return this->traits_; } /// Create a call object for transmitting InfraredCall make_call(); /// Get capability flags for this infrared instance uint32_t get_capability_flags() const; /// Called when IR data is received (from RemoteReceiverListener) bool on_receive(remote_base::RemoteReceiveData data) override; protected: friend class InfraredCall; /// Perform the actual transmission (called by InfraredCall) virtual void control(const InfraredCall &call); // Underlying hardware components remote_base::RemoteReceiverBase *receiver_{nullptr}; remote_base::RemoteTransmitterBase *transmitter_{nullptr}; // Traits describing capabilities InfraredTraits traits_; }; } // namespace esphome::infrared