mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[infrared] Implement experimental API/Core/component for new component/entity type (#13129)
Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
@@ -249,6 +249,7 @@ esphome/components/ina260/* @mreditor97
|
|||||||
esphome/components/ina2xx_base/* @latonita
|
esphome/components/ina2xx_base/* @latonita
|
||||||
esphome/components/ina2xx_i2c/* @latonita
|
esphome/components/ina2xx_i2c/* @latonita
|
||||||
esphome/components/ina2xx_spi/* @latonita
|
esphome/components/ina2xx_spi/* @latonita
|
||||||
|
esphome/components/infrared/* @kbx81
|
||||||
esphome/components/inkbird_ibsth1_mini/* @fkirill
|
esphome/components/inkbird_ibsth1_mini/* @fkirill
|
||||||
esphome/components/inkplate/* @jesserockz @JosipKuci
|
esphome/components/inkplate/* @jesserockz @JosipKuci
|
||||||
esphome/components/integration/* @OttoWinter
|
esphome/components/integration/* @OttoWinter
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ service APIConnection {
|
|||||||
|
|
||||||
rpc zwave_proxy_frame(ZWaveProxyFrame) returns (void) {}
|
rpc zwave_proxy_frame(ZWaveProxyFrame) returns (void) {}
|
||||||
rpc zwave_proxy_request(ZWaveProxyRequest) returns (void) {}
|
rpc zwave_proxy_request(ZWaveProxyRequest) returns (void) {}
|
||||||
|
|
||||||
|
rpc infrared_rf_transmit_raw_timings(InfraredRFTransmitRawTimingsRequest) returns (void) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2437,3 +2439,49 @@ message ZWaveProxyRequest {
|
|||||||
ZWaveProxyRequestType type = 1;
|
ZWaveProxyRequestType type = 1;
|
||||||
bytes data = 2;
|
bytes data = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== INFRARED ====================
|
||||||
|
// Note: Feature and capability flag enums are defined in
|
||||||
|
// esphome/components/infrared/infrared.h
|
||||||
|
|
||||||
|
// Listing of infrared instances
|
||||||
|
message ListEntitiesInfraredResponse {
|
||||||
|
option (id) = 135;
|
||||||
|
option (base_class) = "InfoResponseProtoMessage";
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_INFRARED";
|
||||||
|
|
||||||
|
string object_id = 1;
|
||||||
|
fixed32 key = 2;
|
||||||
|
string name = 3;
|
||||||
|
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON"];
|
||||||
|
bool disabled_by_default = 5;
|
||||||
|
EntityCategory entity_category = 6;
|
||||||
|
uint32 device_id = 7 [(field_ifdef) = "USE_DEVICES"];
|
||||||
|
uint32 capabilities = 8; // Bitfield of InfraredCapabilityFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command to transmit infrared/RF data using raw timings
|
||||||
|
message InfraredRFTransmitRawTimingsRequest {
|
||||||
|
option (id) = 136;
|
||||||
|
option (source) = SOURCE_CLIENT;
|
||||||
|
option (ifdef) = "USE_IR_RF";
|
||||||
|
|
||||||
|
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
|
||||||
|
fixed32 key = 2; // Key identifying the transmitter instance
|
||||||
|
uint32 carrier_frequency = 3; // Carrier frequency in Hz
|
||||||
|
uint32 repeat_count = 4; // Number of times to transmit (1 = once, 2 = twice, etc.)
|
||||||
|
repeated sint32 timings = 5 [packed = true, (packed_buffer) = true]; // Raw timings in microseconds (zigzag-encoded): positive = mark (LED/TX on), negative = space (LED/TX off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event message for received infrared/RF data
|
||||||
|
message InfraredRFReceiveEvent {
|
||||||
|
option (id) = 137;
|
||||||
|
option (source) = SOURCE_SERVER;
|
||||||
|
option (ifdef) = "USE_IR_RF";
|
||||||
|
option (no_delay) = true;
|
||||||
|
|
||||||
|
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
|
||||||
|
fixed32 key = 2; // Key identifying the receiver instance
|
||||||
|
repeated sint32 timings = 3 [packed = true, (container_pointer_no_template) = "std::vector<int32_t>"]; // Raw timings in microseconds (zigzag-encoded): alternating mark/space periods
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,6 +46,9 @@
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
#include "esphome/components/water_heater/water_heater.h"
|
#include "esphome/components/water_heater/water_heater.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
#include "esphome/components/infrared/infrared.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome::api {
|
namespace esphome::api {
|
||||||
|
|
||||||
@@ -1438,6 +1441,35 @@ uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *c
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void APIConnection::infrared_rf_transmit_raw_timings(const InfraredRFTransmitRawTimingsRequest &msg) {
|
||||||
|
// TODO: When RF is implemented, add a field to the message to distinguish IR vs RF
|
||||||
|
// and dispatch to the appropriate entity type based on that field.
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
ENTITY_COMMAND_MAKE_CALL(infrared::Infrared, infrared, infrared)
|
||||||
|
call.set_carrier_frequency(msg.carrier_frequency);
|
||||||
|
call.set_raw_timings_packed(msg.timings_data_, msg.timings_length_, msg.timings_count_);
|
||||||
|
call.set_repeat_count(msg.repeat_count);
|
||||||
|
call.perform();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIConnection::send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg) {
|
||||||
|
this->send_message(msg, InfraredRFReceiveEvent::MESSAGE_TYPE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
uint16_t APIConnection::try_send_infrared_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
|
bool is_single) {
|
||||||
|
auto *infrared = static_cast<infrared::Infrared *>(entity);
|
||||||
|
ListEntitiesInfraredResponse msg;
|
||||||
|
msg.capabilities = infrared->get_capability_flags();
|
||||||
|
return fill_and_encode_entity_info(infrared, msg, ListEntitiesInfraredResponse::MESSAGE_TYPE, conn, remaining_size,
|
||||||
|
is_single);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
bool APIConnection::send_update_state(update::UpdateEntity *update) {
|
bool APIConnection::send_update_state(update::UpdateEntity *update) {
|
||||||
return this->send_message_smart_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE,
|
return this->send_message_smart_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE,
|
||||||
|
|||||||
@@ -172,6 +172,11 @@ class APIConnection final : public APIServerConnection {
|
|||||||
void on_water_heater_command_request(const WaterHeaterCommandRequest &msg) override;
|
void on_water_heater_command_request(const WaterHeaterCommandRequest &msg) override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void infrared_rf_transmit_raw_timings(const InfraredRFTransmitRawTimingsRequest &msg) override;
|
||||||
|
void send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
void send_event(event::Event *event, StringRef event_type);
|
void send_event(event::Event *event, StringRef event_type);
|
||||||
#endif
|
#endif
|
||||||
@@ -468,6 +473,10 @@ class APIConnection final : public APIServerConnection {
|
|||||||
static uint16_t try_send_water_heater_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
static uint16_t try_send_water_heater_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single);
|
bool is_single);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
static uint16_t try_send_infrared_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
|
bool is_single);
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
static uint16_t try_send_event_response(event::Event *event, StringRef event_type, APIConnection *conn,
|
static uint16_t try_send_event_response(event::Event *event, StringRef event_type, APIConnection *conn,
|
||||||
uint32_t remaining_size, bool is_single);
|
uint32_t remaining_size, bool is_single);
|
||||||
|
|||||||
@@ -3347,5 +3347,98 @@ void ZWaveProxyRequest::calculate_size(ProtoSize &size) const {
|
|||||||
size.add_length(1, this->data_len);
|
size.add_length(1, this->data_len);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
void ListEntitiesInfraredResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
|
buffer.encode_string(1, this->object_id);
|
||||||
|
buffer.encode_fixed32(2, this->key);
|
||||||
|
buffer.encode_string(3, this->name);
|
||||||
|
#ifdef USE_ENTITY_ICON
|
||||||
|
buffer.encode_string(4, this->icon);
|
||||||
|
#endif
|
||||||
|
buffer.encode_bool(5, this->disabled_by_default);
|
||||||
|
buffer.encode_uint32(6, static_cast<uint32_t>(this->entity_category));
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
buffer.encode_uint32(7, this->device_id);
|
||||||
|
#endif
|
||||||
|
buffer.encode_uint32(8, this->capabilities);
|
||||||
|
}
|
||||||
|
void ListEntitiesInfraredResponse::calculate_size(ProtoSize &size) const {
|
||||||
|
size.add_length(1, this->object_id.size());
|
||||||
|
size.add_fixed32(1, this->key);
|
||||||
|
size.add_length(1, this->name.size());
|
||||||
|
#ifdef USE_ENTITY_ICON
|
||||||
|
size.add_length(1, this->icon.size());
|
||||||
|
#endif
|
||||||
|
size.add_bool(1, this->disabled_by_default);
|
||||||
|
size.add_uint32(1, static_cast<uint32_t>(this->entity_category));
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
size.add_uint32(1, this->device_id);
|
||||||
|
#endif
|
||||||
|
size.add_uint32(1, this->capabilities);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
bool InfraredRFTransmitRawTimingsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||||
|
switch (field_id) {
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
case 1:
|
||||||
|
this->device_id = value.as_uint32();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 3:
|
||||||
|
this->carrier_frequency = value.as_uint32();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
this->repeat_count = value.as_uint32();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool InfraredRFTransmitRawTimingsRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||||
|
switch (field_id) {
|
||||||
|
case 5: {
|
||||||
|
this->timings_data_ = value.data();
|
||||||
|
this->timings_length_ = value.size();
|
||||||
|
this->timings_count_ = count_packed_varints(value.data(), value.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool InfraredRFTransmitRawTimingsRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||||
|
switch (field_id) {
|
||||||
|
case 2:
|
||||||
|
this->key = value.as_fixed32();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void InfraredRFReceiveEvent::encode(ProtoWriteBuffer buffer) const {
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
buffer.encode_uint32(1, this->device_id);
|
||||||
|
#endif
|
||||||
|
buffer.encode_fixed32(2, this->key);
|
||||||
|
for (const auto &it : *this->timings) {
|
||||||
|
buffer.encode_sint32(3, it, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void InfraredRFReceiveEvent::calculate_size(ProtoSize &size) const {
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
size.add_uint32(1, this->device_id);
|
||||||
|
#endif
|
||||||
|
size.add_fixed32(1, this->key);
|
||||||
|
if (!this->timings->empty()) {
|
||||||
|
for (const auto &it : *this->timings) {
|
||||||
|
size.add_sint32_force(1, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
|||||||
@@ -3049,5 +3049,70 @@ class ZWaveProxyRequest final : public ProtoDecodableMessage {
|
|||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
class ListEntitiesInfraredResponse final : public InfoResponseProtoMessage {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t MESSAGE_TYPE = 135;
|
||||||
|
static constexpr uint8_t ESTIMATED_SIZE = 44;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
const char *message_name() const override { return "list_entities_infrared_response"; }
|
||||||
|
#endif
|
||||||
|
uint32_t capabilities{0};
|
||||||
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
|
void calculate_size(ProtoSize &size) const override;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void dump_to(std::string &out) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
class InfraredRFTransmitRawTimingsRequest final : public ProtoDecodableMessage {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t MESSAGE_TYPE = 136;
|
||||||
|
static constexpr uint8_t ESTIMATED_SIZE = 220;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
const char *message_name() const override { return "infrared_rf_transmit_raw_timings_request"; }
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
uint32_t device_id{0};
|
||||||
|
#endif
|
||||||
|
uint32_t key{0};
|
||||||
|
uint32_t carrier_frequency{0};
|
||||||
|
uint32_t repeat_count{0};
|
||||||
|
const uint8_t *timings_data_{nullptr};
|
||||||
|
uint16_t timings_length_{0};
|
||||||
|
uint16_t timings_count_{0};
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void dump_to(std::string &out) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
|
};
|
||||||
|
class InfraredRFReceiveEvent final : public ProtoMessage {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t MESSAGE_TYPE = 137;
|
||||||
|
static constexpr uint8_t ESTIMATED_SIZE = 17;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
const char *message_name() const override { return "infrared_rf_receive_event"; }
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
uint32_t device_id{0};
|
||||||
|
#endif
|
||||||
|
uint32_t key{0};
|
||||||
|
const std::vector<int32_t> *timings{};
|
||||||
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
|
void calculate_size(ProtoSize &size) const override;
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
void dump_to(std::string &out) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
|||||||
@@ -2309,6 +2309,50 @@ void ZWaveProxyRequest::dump_to(std::string &out) const {
|
|||||||
out.append("\n");
|
out.append("\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
void ListEntitiesInfraredResponse::dump_to(std::string &out) const {
|
||||||
|
MessageDumpHelper helper(out, "ListEntitiesInfraredResponse");
|
||||||
|
dump_field(out, "object_id", this->object_id);
|
||||||
|
dump_field(out, "key", this->key);
|
||||||
|
dump_field(out, "name", this->name);
|
||||||
|
#ifdef USE_ENTITY_ICON
|
||||||
|
dump_field(out, "icon", this->icon);
|
||||||
|
#endif
|
||||||
|
dump_field(out, "disabled_by_default", this->disabled_by_default);
|
||||||
|
dump_field(out, "entity_category", static_cast<enums::EntityCategory>(this->entity_category));
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
dump_field(out, "device_id", this->device_id);
|
||||||
|
#endif
|
||||||
|
dump_field(out, "capabilities", this->capabilities);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void InfraredRFTransmitRawTimingsRequest::dump_to(std::string &out) const {
|
||||||
|
MessageDumpHelper helper(out, "InfraredRFTransmitRawTimingsRequest");
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
dump_field(out, "device_id", this->device_id);
|
||||||
|
#endif
|
||||||
|
dump_field(out, "key", this->key);
|
||||||
|
dump_field(out, "carrier_frequency", this->carrier_frequency);
|
||||||
|
dump_field(out, "repeat_count", this->repeat_count);
|
||||||
|
out.append(" timings: ");
|
||||||
|
out.append("packed buffer [");
|
||||||
|
out.append(std::to_string(this->timings_count_));
|
||||||
|
out.append(" values, ");
|
||||||
|
out.append(std::to_string(this->timings_length_));
|
||||||
|
out.append(" bytes]\n");
|
||||||
|
}
|
||||||
|
void InfraredRFReceiveEvent::dump_to(std::string &out) const {
|
||||||
|
MessageDumpHelper helper(out, "InfraredRFReceiveEvent");
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
dump_field(out, "device_id", this->device_id);
|
||||||
|
#endif
|
||||||
|
dump_field(out, "key", this->key);
|
||||||
|
for (const auto &it : *this->timings) {
|
||||||
|
dump_field(out, "timings", it, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace esphome::api
|
} // namespace esphome::api
|
||||||
|
|
||||||
|
|||||||
@@ -621,6 +621,17 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
|
|||||||
this->on_water_heater_command_request(msg);
|
this->on_water_heater_command_request(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
case InfraredRFTransmitRawTimingsRequest::MESSAGE_TYPE: {
|
||||||
|
InfraredRFTransmitRawTimingsRequest msg;
|
||||||
|
msg.decode(msg_data, msg_size);
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
ESP_LOGVV(TAG, "on_infrared_rf_transmit_raw_timings_request: %s", msg.dump().c_str());
|
||||||
|
#endif
|
||||||
|
this->on_infrared_rf_transmit_raw_timings_request(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -819,6 +830,11 @@ void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) { th
|
|||||||
#ifdef USE_ZWAVE_PROXY
|
#ifdef USE_ZWAVE_PROXY
|
||||||
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) { this->zwave_proxy_request(msg); }
|
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) { this->zwave_proxy_request(msg); }
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void APIServerConnection::on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg) {
|
||||||
|
this->infrared_rf_transmit_raw_timings(msg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {
|
void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {
|
||||||
// Check authentication/connection requirements for messages
|
// Check authentication/connection requirements for messages
|
||||||
|
|||||||
@@ -217,6 +217,11 @@ class APIServerConnectionBase : public ProtoService {
|
|||||||
#ifdef USE_ZWAVE_PROXY
|
#ifdef USE_ZWAVE_PROXY
|
||||||
virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
|
virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
virtual void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &value){};
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
|
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
|
||||||
};
|
};
|
||||||
@@ -347,6 +352,9 @@ class APIServerConnection : public APIServerConnectionBase {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef USE_ZWAVE_PROXY
|
#ifdef USE_ZWAVE_PROXY
|
||||||
virtual void zwave_proxy_request(const ZWaveProxyRequest &msg) = 0;
|
virtual void zwave_proxy_request(const ZWaveProxyRequest &msg) = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
virtual void infrared_rf_transmit_raw_timings(const InfraredRFTransmitRawTimingsRequest &msg) = 0;
|
||||||
#endif
|
#endif
|
||||||
protected:
|
protected:
|
||||||
void on_hello_request(const HelloRequest &msg) override;
|
void on_hello_request(const HelloRequest &msg) override;
|
||||||
@@ -473,6 +481,9 @@ class APIServerConnection : public APIServerConnectionBase {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef USE_ZWAVE_PROXY
|
#ifdef USE_ZWAVE_PROXY
|
||||||
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override;
|
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg) override;
|
||||||
#endif
|
#endif
|
||||||
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
|
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -347,6 +347,21 @@ void APIServer::on_zwave_proxy_request(const esphome::api::ProtoMessage &msg) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void APIServer::send_infrared_rf_receive_event([[maybe_unused]] uint32_t device_id, uint32_t key,
|
||||||
|
const std::vector<int32_t> *timings) {
|
||||||
|
InfraredRFReceiveEvent resp{};
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
resp.device_id = device_id;
|
||||||
|
#endif
|
||||||
|
resp.key = key;
|
||||||
|
resp.timings = timings;
|
||||||
|
|
||||||
|
for (auto &c : this->clients_)
|
||||||
|
c->send_infrared_rf_receive_event(resp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
|
API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -185,6 +185,9 @@ class APIServer : public Component,
|
|||||||
#ifdef USE_ZWAVE_PROXY
|
#ifdef USE_ZWAVE_PROXY
|
||||||
void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg);
|
void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_IR_RF
|
||||||
|
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector<int32_t> *timings);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool is_connected(bool state_subscription_only = false) const;
|
bool is_connected(bool state_subscription_only = false) const;
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ LIST_ENTITIES_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPane
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
LIST_ENTITIES_HANDLER(water_heater, water_heater::WaterHeater, ListEntitiesWaterHeaterResponse)
|
LIST_ENTITIES_HANDLER(water_heater, water_heater::WaterHeater, ListEntitiesWaterHeaterResponse)
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
LIST_ENTITIES_HANDLER(infrared, infrared::Infrared, ListEntitiesInfraredResponse)
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse)
|
LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ class ListEntitiesIterator : public ComponentIterator {
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
bool on_water_heater(water_heater::WaterHeater *entity) override;
|
bool on_water_heater(water_heater::WaterHeater *entity) override;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
bool on_infrared(infrared::Infrared *entity) override;
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
bool on_event(event::Event *entity) override;
|
bool on_event(event::Event *entity) override;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ class InitialStateIterator : public ComponentIterator {
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
bool on_water_heater(water_heater::WaterHeater *entity) override;
|
bool on_water_heater(water_heater::WaterHeater *entity) override;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
bool on_infrared(infrared::Infrared *infrared) override { return true; };
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
bool on_event(event::Event *event) override { return true; };
|
bool on_event(event::Event *event) override { return true; };
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
76
esphome/components/infrared/__init__.py
Normal file
76
esphome/components/infrared/__init__.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
"""
|
||||||
|
Infrared component for ESPHome.
|
||||||
|
|
||||||
|
WARNING: This component is EXPERIMENTAL. The API (both Python configuration
|
||||||
|
and C++ interfaces) 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
from esphome.core.entity_helpers import setup_entity
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
from esphome.types import ConfigType
|
||||||
|
|
||||||
|
CODEOWNERS = ["@kbx81"]
|
||||||
|
AUTO_LOAD = ["remote_base"]
|
||||||
|
|
||||||
|
IS_PLATFORM_COMPONENT = True
|
||||||
|
|
||||||
|
infrared_ns = cg.esphome_ns.namespace("infrared")
|
||||||
|
Infrared = infrared_ns.class_("Infrared", cg.EntityBase, cg.Component)
|
||||||
|
InfraredCall = infrared_ns.class_("InfraredCall")
|
||||||
|
InfraredTraits = infrared_ns.class_("InfraredTraits")
|
||||||
|
|
||||||
|
CONF_INFRARED_ID = "infrared_id"
|
||||||
|
CONF_SUPPORTS_TRANSMITTER = "supports_transmitter"
|
||||||
|
CONF_SUPPORTS_RECEIVER = "supports_receiver"
|
||||||
|
|
||||||
|
|
||||||
|
def infrared_schema(class_: type[cg.MockObjClass]) -> cv.Schema:
|
||||||
|
"""Create a schema for an infrared platform.
|
||||||
|
|
||||||
|
:param class_: The infrared class to use for this schema.
|
||||||
|
:return: An extended schema for infrared configuration.
|
||||||
|
"""
|
||||||
|
entity_schema = cv.ENTITY_BASE_SCHEMA.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
return entity_schema.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(class_),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_infrared_core_(var: cg.Pvariable, config: ConfigType) -> None:
|
||||||
|
"""Set up core infrared configuration."""
|
||||||
|
await setup_entity(var, config, "infrared")
|
||||||
|
|
||||||
|
|
||||||
|
async def register_infrared(var: cg.Pvariable, config: ConfigType) -> None:
|
||||||
|
"""Register an infrared device with the core."""
|
||||||
|
cg.add_define("USE_IR_RF")
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await setup_infrared_core_(var, config)
|
||||||
|
cg.add(cg.App.register_infrared(var))
|
||||||
|
CORE.register_platform_component("infrared", var)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_infrared(config: ConfigType, *args) -> cg.Pvariable:
|
||||||
|
"""Create a new Infrared instance.
|
||||||
|
|
||||||
|
:param config: Configuration dictionary.
|
||||||
|
:param args: Additional arguments to pass to new_Pvariable.
|
||||||
|
:return: The created Infrared instance.
|
||||||
|
"""
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID], *args)
|
||||||
|
await register_infrared(var, config)
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@coroutine_with_priority(CoroPriority.CORE)
|
||||||
|
async def to_code(config: ConfigType) -> None:
|
||||||
|
cg.add_global(infrared_ns.using)
|
||||||
150
esphome/components/infrared/infrared.cpp
Normal file
150
esphome/components/infrared/infrared.cpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#include "infrared.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
#ifdef USE_API
|
||||||
|
#include "esphome/components/api/api_server.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace esphome::infrared {
|
||||||
|
|
||||||
|
static const char *const TAG = "infrared";
|
||||||
|
|
||||||
|
// ========== InfraredCall ==========
|
||||||
|
|
||||||
|
InfraredCall &InfraredCall::set_carrier_frequency(uint32_t frequency) {
|
||||||
|
this->carrier_frequency_ = frequency;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfraredCall &InfraredCall::set_raw_timings(const std::vector<int32_t> &timings) {
|
||||||
|
this->raw_timings_ = &timings;
|
||||||
|
this->packed_data_ = nullptr; // Clear packed if vector is set
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfraredCall &InfraredCall::set_raw_timings_packed(const uint8_t *data, uint16_t length, uint16_t count) {
|
||||||
|
this->packed_data_ = data;
|
||||||
|
this->packed_length_ = length;
|
||||||
|
this->packed_count_ = count;
|
||||||
|
this->raw_timings_ = nullptr; // Clear vector if packed is set
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfraredCall &InfraredCall::set_repeat_count(uint32_t count) {
|
||||||
|
this->repeat_count_ = count;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfraredCall::perform() {
|
||||||
|
if (this->parent_ != nullptr) {
|
||||||
|
this->parent_->control(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== Infrared ==========
|
||||||
|
|
||||||
|
void Infrared::setup() {
|
||||||
|
// Set up traits based on configuration
|
||||||
|
this->traits_.set_supports_transmitter(this->has_transmitter());
|
||||||
|
this->traits_.set_supports_receiver(this->has_receiver());
|
||||||
|
|
||||||
|
// Register as listener for received IR data
|
||||||
|
if (this->receiver_ != nullptr) {
|
||||||
|
this->receiver_->register_listener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Infrared::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG,
|
||||||
|
"Infrared '%s'\n"
|
||||||
|
" Supports Transmitter: %s\n"
|
||||||
|
" Supports Receiver: %s",
|
||||||
|
this->get_name().c_str(), YESNO(this->traits_.get_supports_transmitter()),
|
||||||
|
YESNO(this->traits_.get_supports_receiver()));
|
||||||
|
}
|
||||||
|
|
||||||
|
InfraredCall Infrared::make_call() { return InfraredCall(this); }
|
||||||
|
|
||||||
|
void Infrared::control(const InfraredCall &call) {
|
||||||
|
if (this->transmitter_ == nullptr) {
|
||||||
|
ESP_LOGW(TAG, "No transmitter configured");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!call.has_raw_timings()) {
|
||||||
|
ESP_LOGE(TAG, "No raw timings provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create transmit data object
|
||||||
|
auto transmit_call = this->transmitter_->transmit();
|
||||||
|
auto *transmit_data = transmit_call.get_data();
|
||||||
|
|
||||||
|
// Set carrier frequency
|
||||||
|
if (call.get_carrier_frequency().has_value()) {
|
||||||
|
transmit_data->set_carrier_frequency(call.get_carrier_frequency().value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timings based on format
|
||||||
|
if (call.is_packed()) {
|
||||||
|
// Zero-copy from packed protobuf data
|
||||||
|
ESP_LOGD(TAG, "Transmitting raw timings: timing_count=%u, repeat_count=%u", call.get_packed_count(),
|
||||||
|
call.get_repeat_count());
|
||||||
|
transmit_data->set_data_from_packed_sint32(call.get_packed_data(), call.get_packed_length(),
|
||||||
|
call.get_packed_count());
|
||||||
|
} else {
|
||||||
|
// From vector (lambdas/automations)
|
||||||
|
const auto &timings = call.get_raw_timings();
|
||||||
|
if (timings.empty()) {
|
||||||
|
ESP_LOGE(TAG, "Raw timings array is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "Transmitting raw timings: timing_count=%zu, repeat_count=%u", timings.size(),
|
||||||
|
call.get_repeat_count());
|
||||||
|
// Timings format: positive values = mark (LED on), negative values = space (LED off)
|
||||||
|
for (const auto &timing : timings) {
|
||||||
|
if (timing > 0) {
|
||||||
|
transmit_data->mark(static_cast<uint32_t>(timing));
|
||||||
|
} else {
|
||||||
|
transmit_data->space(static_cast<uint32_t>(-timing));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set repeat count
|
||||||
|
if (call.get_repeat_count() > 0) {
|
||||||
|
transmit_call.set_send_times(call.get_repeat_count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform transmission
|
||||||
|
transmit_call.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Infrared::get_capability_flags() const {
|
||||||
|
uint32_t flags = 0;
|
||||||
|
|
||||||
|
// Add transmit/receive capability based on traits
|
||||||
|
if (this->traits_.get_supports_transmitter())
|
||||||
|
flags |= InfraredCapability::CAPABILITY_TRANSMITTER;
|
||||||
|
if (this->traits_.get_supports_receiver())
|
||||||
|
flags |= InfraredCapability::CAPABILITY_RECEIVER;
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Infrared::on_receive(remote_base::RemoteReceiveData data) {
|
||||||
|
// Forward received IR data to API server
|
||||||
|
#if defined(USE_API) && defined(USE_IR_RF)
|
||||||
|
if (api::global_api_server != nullptr) {
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
uint32_t device_id = this->get_device_id();
|
||||||
|
#else
|
||||||
|
uint32_t device_id = 0;
|
||||||
|
#endif
|
||||||
|
api::global_api_server->send_infrared_rf_receive_event(device_id, this->get_object_id_hash(), &data.get_raw_data());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false; // Don't consume the event, allow other listeners to process it
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome::infrared
|
||||||
130
esphome/components/infrared/infrared.h
Normal file
130
esphome/components/infrared/infrared.h
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#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 <vector>
|
||||||
|
|
||||||
|
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);
|
||||||
|
/// Set the raw timings (positive = mark, negative = space)
|
||||||
|
/// Note: The timings vector must outlive the InfraredCall (zero-copy reference)
|
||||||
|
InfraredCall &set_raw_timings(const std::vector<int32_t> &timings);
|
||||||
|
/// Set the raw timings from packed protobuf sint32 data (zero-copy from wire)
|
||||||
|
/// Note: The data must outlive the InfraredCall
|
||||||
|
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<uint32_t> &get_carrier_frequency() const { return this->carrier_frequency_; }
|
||||||
|
/// Get the raw timings (only valid if set via set_raw_timings, not packed)
|
||||||
|
const std::vector<int32_t> &get_raw_timings() const { return *this->raw_timings_; }
|
||||||
|
/// Check if raw timings have been set (either vector or packed)
|
||||||
|
bool has_raw_timings() const { return this->raw_timings_ != nullptr || this->packed_data_ != nullptr; }
|
||||||
|
/// Check if using packed data format
|
||||||
|
bool is_packed() const { return this->packed_data_ != nullptr; }
|
||||||
|
/// 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<uint32_t> carrier_frequency_;
|
||||||
|
// Vector-based timings (for lambdas/automations)
|
||||||
|
const std::vector<int32_t> *raw_timings_{nullptr};
|
||||||
|
// Packed protobuf timings (for API zero-copy)
|
||||||
|
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; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool supports_transmitter_{false};
|
||||||
|
bool supports_receiver_{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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
|
||||||
@@ -141,6 +141,13 @@ bool ListEntitiesIterator::on_water_heater(water_heater::WaterHeater *obj) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
bool ListEntitiesIterator::on_infrared(infrared::Infrared *obj) {
|
||||||
|
// Infrared web_server support not yet implemented - this stub acknowledges the entity
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
bool ListEntitiesIterator::on_event(event::Event *obj) {
|
bool ListEntitiesIterator::on_event(event::Event *obj) {
|
||||||
// Null event type, since we are just iterating over entities
|
// Null event type, since we are just iterating over entities
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ class ListEntitiesIterator : public ComponentIterator {
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
bool on_water_heater(water_heater::WaterHeater *obj) override;
|
bool on_water_heater(water_heater::WaterHeater *obj) override;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
bool on_infrared(infrared::Infrared *obj) override;
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
bool on_event(event::Event *obj) override;
|
bool on_event(event::Event *obj) override;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -91,6 +91,9 @@
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
#include "esphome/components/water_heater/water_heater.h"
|
#include "esphome/components/water_heater/water_heater.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
#include "esphome/components/infrared/infrared.h"
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
#include "esphome/components/event/event.h"
|
#include "esphome/components/event/event.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -223,6 +226,10 @@ class Application {
|
|||||||
void register_water_heater(water_heater::WaterHeater *water_heater) { this->water_heaters_.push_back(water_heater); }
|
void register_water_heater(water_heater::WaterHeater *water_heater) { this->water_heaters_.push_back(water_heater); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
void register_infrared(infrared::Infrared *infrared) { this->infrareds_.push_back(infrared); }
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
void register_event(event::Event *event) { this->events_.push_back(event); }
|
void register_event(event::Event *event) { this->events_.push_back(event); }
|
||||||
#endif
|
#endif
|
||||||
@@ -457,6 +464,11 @@ class Application {
|
|||||||
GET_ENTITY_METHOD(water_heater::WaterHeater, water_heater, water_heaters)
|
GET_ENTITY_METHOD(water_heater::WaterHeater, water_heater, water_heaters)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
auto &get_infrareds() const { return this->infrareds_; }
|
||||||
|
GET_ENTITY_METHOD(infrared::Infrared, infrared, infrareds)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
auto &get_events() const { return this->events_; }
|
auto &get_events() const { return this->events_; }
|
||||||
GET_ENTITY_METHOD(event::Event, event, events)
|
GET_ENTITY_METHOD(event::Event, event, events)
|
||||||
@@ -656,6 +668,9 @@ class Application {
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
StaticVector<water_heater::WaterHeater *, ESPHOME_ENTITY_WATER_HEATER_COUNT> water_heaters_{};
|
StaticVector<water_heater::WaterHeater *, ESPHOME_ENTITY_WATER_HEATER_COUNT> water_heaters_{};
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
StaticVector<infrared::Infrared *, ESPHOME_ENTITY_INFRARED_COUNT> infrareds_{};
|
||||||
|
#endif
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
StaticVector<update::UpdateEntity *, ESPHOME_ENTITY_UPDATE_COUNT> updates_{};
|
StaticVector<update::UpdateEntity *, ESPHOME_ENTITY_UPDATE_COUNT> updates_{};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -169,6 +169,12 @@ void ComponentIterator::advance() {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
case IteratorState::INFRARED:
|
||||||
|
this->process_platform_item_(App.get_infrareds(), &ComponentIterator::on_infrared);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
case IteratorState::EVENT:
|
case IteratorState::EVENT:
|
||||||
this->process_platform_item_(App.get_events(), &ComponentIterator::on_event);
|
this->process_platform_item_(App.get_events(), &ComponentIterator::on_event);
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ class UserServiceDescriptor;
|
|||||||
} // namespace api
|
} // namespace api
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
namespace infrared {
|
||||||
|
class Infrared;
|
||||||
|
} // namespace infrared
|
||||||
|
#endif
|
||||||
|
|
||||||
class ComponentIterator {
|
class ComponentIterator {
|
||||||
public:
|
public:
|
||||||
void begin(bool include_internal = false);
|
void begin(bool include_internal = false);
|
||||||
@@ -87,6 +93,9 @@ class ComponentIterator {
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
virtual bool on_water_heater(water_heater::WaterHeater *water_heater) = 0;
|
virtual bool on_water_heater(water_heater::WaterHeater *water_heater) = 0;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
virtual bool on_infrared(infrared::Infrared *infrared) = 0;
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
virtual bool on_event(event::Event *event) = 0;
|
virtual bool on_event(event::Event *event) = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -167,6 +176,9 @@ class ComponentIterator {
|
|||||||
#ifdef USE_WATER_HEATER
|
#ifdef USE_WATER_HEATER
|
||||||
WATER_HEATER,
|
WATER_HEATER,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_INFRARED
|
||||||
|
INFRARED,
|
||||||
|
#endif
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
EVENT,
|
EVENT,
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
#define USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT 8000 // NOLINT
|
#define USE_HTTP_REQUEST_OTA_WATCHDOG_TIMEOUT 8000 // NOLINT
|
||||||
#define USE_IMAGE
|
#define USE_IMAGE
|
||||||
#define USE_IMPROV_SERIAL_NEXT_URL
|
#define USE_IMPROV_SERIAL_NEXT_URL
|
||||||
|
#define USE_INFRARED
|
||||||
|
#define USE_IR_RF
|
||||||
#define USE_JSON
|
#define USE_JSON
|
||||||
#define USE_LIGHT
|
#define USE_LIGHT
|
||||||
#define USE_LOCK
|
#define USE_LOCK
|
||||||
@@ -321,9 +323,9 @@
|
|||||||
|
|
||||||
// Default counts for static analysis
|
// Default counts for static analysis
|
||||||
#define CONTROLLER_REGISTRY_MAX 2
|
#define CONTROLLER_REGISTRY_MAX 2
|
||||||
|
#define ESPHOME_AREA_COUNT 10
|
||||||
#define ESPHOME_COMPONENT_COUNT 50
|
#define ESPHOME_COMPONENT_COUNT 50
|
||||||
#define ESPHOME_DEVICE_COUNT 10
|
#define ESPHOME_DEVICE_COUNT 10
|
||||||
#define ESPHOME_AREA_COUNT 10
|
|
||||||
#define ESPHOME_ENTITY_ALARM_CONTROL_PANEL_COUNT 1
|
#define ESPHOME_ENTITY_ALARM_CONTROL_PANEL_COUNT 1
|
||||||
#define ESPHOME_ENTITY_BINARY_SENSOR_COUNT 1
|
#define ESPHOME_ENTITY_BINARY_SENSOR_COUNT 1
|
||||||
#define ESPHOME_ENTITY_BUTTON_COUNT 1
|
#define ESPHOME_ENTITY_BUTTON_COUNT 1
|
||||||
@@ -333,6 +335,7 @@
|
|||||||
#define ESPHOME_ENTITY_DATETIME_COUNT 1
|
#define ESPHOME_ENTITY_DATETIME_COUNT 1
|
||||||
#define ESPHOME_ENTITY_EVENT_COUNT 1
|
#define ESPHOME_ENTITY_EVENT_COUNT 1
|
||||||
#define ESPHOME_ENTITY_FAN_COUNT 1
|
#define ESPHOME_ENTITY_FAN_COUNT 1
|
||||||
|
#define ESPHOME_ENTITY_INFRARED_COUNT 1
|
||||||
#define ESPHOME_ENTITY_LIGHT_COUNT 1
|
#define ESPHOME_ENTITY_LIGHT_COUNT 1
|
||||||
#define ESPHOME_ENTITY_LOCK_COUNT 1
|
#define ESPHOME_ENTITY_LOCK_COUNT 1
|
||||||
#define ESPHOME_ENTITY_MEDIA_PLAYER_COUNT 1
|
#define ESPHOME_ENTITY_MEDIA_PLAYER_COUNT 1
|
||||||
|
|||||||
@@ -37,3 +37,4 @@ datetime:
|
|||||||
event:
|
event:
|
||||||
update:
|
update:
|
||||||
water_heater:
|
water_heater:
|
||||||
|
infrared:
|
||||||
|
|||||||
Reference in New Issue
Block a user