18#if defined(USE_API) && defined(USE_IR_RF)
21static constexpr uint32_t API_REPLY_TIMEOUT_MS = 30000;
23#ifdef USE_IR_RF_TRANSMIT_COMPLETE
26static constexpr uint16_t API_REPLY_MAX_AIR_TICKS = 30000;
29#if defined(USE_API) && defined(USE_IR_RF)
30static uint16_t api_reply_ticks_from_now() {
45 ESP_LOGW(TAG,
"No transmitter configured");
49 if (!
call.has_raw_timings()) {
50 ESP_LOGE(TAG,
"No raw timings provided");
55 auto *transmit_data = transmit_call.
get_data();
58 if (
call.is_packed()) {
60 transmit_data->set_data_from_packed_sint32(
call.get_packed_data(),
call.get_packed_length(),
61 call.get_packed_count());
62 ESP_LOGD(TAG,
"Transmitting packed raw timings: count=%" PRIu16
", repeat=%" PRIu32,
call.get_packed_count(),
63 call.get_repeat_count());
64 }
else if (
call.is_base64url()) {
66 if (!transmit_data->set_data_from_base64url(
call.get_base64url_data())) {
67 ESP_LOGE(TAG,
"Invalid base64url data");
70 constexpr int32_t max_timing_us = 500000;
71 for (int32_t timing : transmit_data->get_data()) {
72 int32_t abs_timing = timing < 0 ? -timing : timing;
73 if (abs_timing > max_timing_us) {
74 ESP_LOGE(TAG,
"Invalid timing value: %" PRId32
" µs (max %" PRId32
")", timing, max_timing_us);
78 ESP_LOGD(TAG,
"Transmitting base64url raw timings: count=%zu, repeat=%" PRIu32, transmit_data->get_data().size(),
79 call.get_repeat_count());
82 transmit_data->set_data(
call.get_raw_timings());
83 ESP_LOGD(TAG,
"Transmitting raw timings: count=%zu, repeat=%" PRIu32,
call.get_raw_timings().size(),
84 call.get_repeat_count());
88 if (transmit_data->get_data().empty()) {
89 ESP_LOGE(TAG,
"No raw timings provided");
93 if (
call.get_repeat_count() > 0) {
94 transmit_call.set_send_times(
call.get_repeat_count());
97#ifdef USE_IR_RF_TRANSMIT_COMPLETE
103 uint64_t frame_us = 0;
104 for (
const int64_t timing : transmit_data->get_data())
105 frame_us += timing < 0 ? -timing : timing;
106 const uint64_t air_ticks = (frame_us * std::max<uint32_t>(
call.get_repeat_count(), 1) / 1000) >> 4;
107 this->
api_reply_deadline_ +=
static_cast<uint16_t
>(std::min<uint64_t>(air_ticks, API_REPLY_MAX_AIR_TICKS));
110 transmit_call.perform();
115#if defined(USE_API) && defined(USE_IR_RF)
128#if defined(USE_API) && defined(USE_IR_RF)
130#ifdef USE_IR_RF_TRANSMIT_COMPLETE
146 ESP_LOGW(TAG,
"'%s': transmit %s", this->
get_name().c_str(), LOG_STR_LITERAL(
"refused, reply still owed"));
163 API_LOG_MSG_DROPPED(TAG,
"IR/RF reply");
201 ESP_LOGW(TAG,
"'%s': transmit %s", this->
get_name().c_str(), LOG_STR_LITERAL(
"reply dropped, client not reading"));
207 ESP_LOGW(TAG,
"'%s': transmit %s", this->
get_name().c_str(), LOG_STR_LITERAL(
"never reported completion"));
220#ifdef USE_IR_RF_TRANSMIT_COMPLETE
225 for (
auto *entity :
App.get_infrareds()) {
226 entity->on_transmit_complete(transmitter,
seq, sent);
229#ifdef USE_RADIO_FREQUENCY
230 for (
auto *entity :
App.get_radio_frequencies()) {
231 entity->on_transmit_complete(transmitter,
seq, sent);
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void disable_loop()
Disable this component's loop.
const StringRef & get_name() const
uint32_t get_object_id_hash() const
uint32_t get_device_id() const
bool send_infrared_rf_transmit_complete(uint32_t device_id, uint32_t key, bool success)
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector< int32_t > *timings)
Raw timings of a transmit call, in one of three caller-owned forms.
void on_transmit_complete(remote_base::RemoteTransmitterBase *transmitter, uint16_t seq, bool sent)
Called for every finished frame on every transmitter; answers the API request when the frame is the o...
void refuse_api_call_(api::APIConnection *conn)
api::APIConnection * api_reply_connection_
bool on_receive(remote_base::RemoteReceiveData data) override
Forwards a received frame to the API; never consumes it, so other listeners still run.
bool expect_api_reply_(api::APIConnection *conn)
Claims the reply slot for conn; false when it still owes a reply that cannot be sent.
remote_base::RemoteTransmitterBase * transmitter_
bool has_receiver() const
void setup() override
Reports the configured transports, listens on the receiver and hooks the transmitter's completion; a ...
bool has_transmitter() const
uint16_t api_reply_deadline_
void finish_api_reply_(bool success)
bool transmit_raw_(const IrRfCallData &call, uint32_t carrier_frequency_hz)
Hands the call's timings to the transmitter; the default transmit path of both entity types.
bool supports_transmitter_
void on_api_connection_closed(api::APIConnection *conn)
The API server calls this when a client disconnects, so no reply goes to a stale pointer.
const RawTimings & get_raw_data() const
void set_carrier_frequency(uint32_t carrier_frequency)
RemoteTransmitData * get_data()
APIServer * global_api_server
ESPHOME_LOG_TAG(TAG, "ir_rf")
void ir_rf_transmit_complete(RemoteTransmitterBase *transmitter, uint16_t seq, bool sent)
Defined by ir_rf_base: answers the API request waiting on the entity that submitted seq; sent is fals...
Application App
Global storage of Application pointer - only one Application can exist.