diff --git a/esphome/components/sx127x/__init__.py b/esphome/components/sx127x/__init__.py index 6bc55a97cd..495528793c 100644 --- a/esphome/components/sx127x/__init__.py +++ b/esphome/components/sx127x/__init__.py @@ -2,7 +2,7 @@ from esphome import automation, pins import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv -from esphome.const import CONF_FREQUENCY, CONF_ID +from esphome.const import CONF_DATA, CONF_FREQUENCY, CONF_ID from esphome.core import TimePeriod CODEOWNERS = ["@swoboda1337"] @@ -48,7 +48,7 @@ SHAPING = { "GAUSSIAN_BT_0_3": SX127xPaRamp.GAUSSIAN_BT_0_3, "GAUSSIAN_BT_0_5": SX127xPaRamp.GAUSSIAN_BT_0_5, "GAUSSIAN_BT_1_0": SX127xPaRamp.GAUSSIAN_BT_1_0, - "NO_SHAPING": SX127xPaRamp.NO_SHAPING, + "NONE": SX127xPaRamp.SHAPING_NONE, } RAMP = { @@ -99,6 +99,26 @@ RX_BW = { "250_0kHz": SX127xRxBw.RX_BW_250_0, } +SendPacketAction = sx127x_ns.class_( + "SendPacketAction", automation.Action, cg.Parented.template(SX127x) +) +SetModeTxAction = sx127x_ns.class_("SetModeTxAction", automation.Action) +SetModeRxAction = sx127x_ns.class_("SetModeRxAction", automation.Action) +SetModeStandbyAction = sx127x_ns.class_("SetModeStandbyAction", automation.Action) + + +def validate_raw_data(value): + if isinstance(value, str): + return value.encode("utf-8") + if isinstance(value, str): + return value + if isinstance(value, list): + return cv.Schema([cv.hex_uint8_t])(value) + raise cv.Invalid( + "data must either be a string wrapped in quotes or a list of bytes" + ) + + CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(SX127x), @@ -108,7 +128,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Required(CONF_NSS_PIN): pins.internal_gpio_output_pin_schema, cv.Required(CONF_FREQUENCY): cv.int_range(min=137000000, max=1020000000), cv.Required(CONF_MODULATION): cv.enum(MOD), - cv.Optional(CONF_SHAPING, default="NO_SHAPING"): cv.enum(SHAPING), + cv.Optional(CONF_SHAPING, default="NONE"): cv.enum(SHAPING), cv.Optional(CONF_BITRATE, default=0): cv.int_range(min=0, max=300000), cv.Optional(CONF_FSK_FDEV, default=5000): cv.int_range(min=0, max=100000), cv.Optional(CONF_FSK_RAMP, default="40us"): cv.enum(RAMP), @@ -170,3 +190,51 @@ async def to_code(config): cg.add(var.set_pa_power(config[CONF_PA_POWER])) cg.add(var.set_fsk_fdev(config[CONF_FSK_FDEV])) cg.add(var.set_fsk_ramp(config[CONF_FSK_RAMP])) + + +SET_MODE_ACTION_SCHEMA = automation.maybe_simple_id( + { + cv.GenerateID(): cv.use_id(SX127x), + } +) + + +@automation.register_action( + "sx127x.set_mode_tx", SetModeTxAction, SET_MODE_ACTION_SCHEMA +) +@automation.register_action( + "sx127x.set_mode_rx", SetModeRxAction, SET_MODE_ACTION_SCHEMA +) +@automation.register_action( + "sx127x.set_mode_standby", SetModeStandbyAction, SET_MODE_ACTION_SCHEMA +) +async def set_mode_action_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + var = cg.new_Pvariable(action_id, template_arg, paren) + return var + + +SEND_PACKET_ACTION_SCHEMA = cv.maybe_simple_value( + { + cv.GenerateID(): cv.use_id(SX127x), + cv.Required(CONF_DATA): cv.templatable(validate_raw_data), + }, + key=CONF_DATA, +) + + +@automation.register_action( + "sx127x.send_packet", SendPacketAction, SEND_PACKET_ACTION_SCHEMA +) +async def send_packet_action_to_code(config, action_id, template_arg, args): + var = cg.new_Pvariable(action_id, template_arg) + await cg.register_parented(var, config[CONF_ID]) + data = config[CONF_DATA] + if isinstance(data, bytes): + data = list(data) + if cg.is_template(data): + templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) + cg.add(var.set_data_template(templ)) + else: + cg.add(var.set_data_static(data)) + return var diff --git a/esphome/components/sx127x/automation.h b/esphome/components/sx127x/automation.h new file mode 100755 index 0000000000..86faf4873d --- /dev/null +++ b/esphome/components/sx127x/automation.h @@ -0,0 +1,66 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/sx127x/sx127x.h" + +namespace esphome { +namespace sx127x { + +template class SendPacketAction : public Action, public Parented { + public: + void set_data_template(std::function(Ts...)> func) { + this->data_func_ = func; + this->static_ = false; + } + void set_data_static(const std::vector &data) { + this->data_static_ = data; + this->static_ = true; + } + + void play(Ts... x) override { + if (this->static_) { + this->parent_->transmit_packet(this->data_static_); + } else { + this->parent_->transmit_packet(this->data_func_(x...)); + } + } + + protected: + bool static_{false}; + std::function(Ts...)> data_func_{}; + std::vector data_static_{}; +}; + +template class SetModeTxAction : public Action { + public: + SetModeTxAction(SX127x *sx127x) : sx127x_(sx127x) {} + + void play(Ts... x) override { this->sx127x_->set_mode_tx(); } + + protected: + SX127x *sx127x_; +}; + +template class SetModeRxAction : public Action { + public: + SetModeRxAction(SX127x *sx127x) : sx127x_(sx127x) {} + + void play(Ts... x) override { this->sx127x_->set_mode_rx(); } + + protected: + SX127x *sx127x_; +}; + +template class SetModeStandbyAction : public Action { + public: + SetModeStandbyAction(SX127x *sx127x) : sx127x_(sx127x) {} + + void play(Ts... x) override { this->sx127x_->set_mode_standby(); } + + protected: + SX127x *sx127x_; +}; + +} // namespace sx127x +} // namespace esphome diff --git a/esphome/components/sx127x/sx127x.cpp b/esphome/components/sx127x/sx127x.cpp index 167d3772cb..7c008bba5b 100644 --- a/esphome/components/sx127x/sx127x.cpp +++ b/esphome/components/sx127x/sx127x.cpp @@ -8,7 +8,7 @@ namespace sx127x { static const char *const TAG = "sx127x"; void IRAM_ATTR HOT SX127xStore::gpio_intr(SX127xStore *arg) { - if (arg->dio2_toggle) { + if (arg->dio2_set && arg->dio2_toggle) { arg->dio2_pin.pin_mode(gpio::FLAG_INPUT); } arg->dio0_micros = micros(); @@ -73,7 +73,7 @@ void SX127x::setup() { this->dio2_pin_->setup(); this->dio2_pin_->pin_mode(gpio::FLAG_OPEN_DRAIN); this->store_.dio2_pin = this->dio2_pin_->to_isr(); - this->store_.dio2_toggle = true; + this->store_.dio2_set = true; } // start spi @@ -202,6 +202,7 @@ void SX127x::configure() { // clear irq flag this->store_.dio0_irq = false; + this->store_.dio2_toggle = (this->rx_duration_ > 0 && this->payload_length_ == 0); // enable standby mode this->set_mode_standby(); @@ -260,7 +261,11 @@ void SX127x::set_mode_rx() { if (this->dio2_pin_) { this->write_register_(REG_OP_MODE, this->modulation_ | MODE_STDBY); delay(1); - this->dio2_pin_->pin_mode(this->modulation_ == MOD_OOK ? gpio::FLAG_INPUT : gpio::FLAG_OPEN_DRAIN); + if (this->rx_duration_ > 0 && this->payload_length_ == 0) { + this->dio2_pin_->pin_mode(gpio::FLAG_OPEN_DRAIN); + } else { + this->dio2_pin_->pin_mode(gpio::FLAG_INPUT); + } } this->write_register_(REG_OP_MODE, this->modulation_ | MODE_RX_FS); delay(1); @@ -303,11 +308,11 @@ void SX127x::dump_config() { ESP_LOGCONFIG(TAG, " Sync Value: 0x%s", format_hex(this->sync_value_).c_str()); } if (this->modulation_ == MOD_FSK) { - static const char *shaping_lut[4] = {"NO_SHAPING", "GAUSSIAN_BT_1_0", "GAUSSIAN_BT_0_5", "GAUSSIAN_BT_0_3"}; - ESP_LOGCONFIG(TAG, " Shaping: %s", shaping_lut[this->shaping_ >> 5]); + static const char *shaping_lut[4] = {"NONE", "GAUSSIAN_BT_1_0", "GAUSSIAN_BT_0_5", "GAUSSIAN_BT_0_3"}; + ESP_LOGCONFIG(TAG, " Shaping: %s", shaping_lut[this->shaping_ >> SHAPING_SHIFT]); } else { - static const char *shaping_lut[4] = {"NO_SHAPING", "CUTOFF_BR_X_1", "CUTOFF_BR_X_2", "ERROR"}; - ESP_LOGCONFIG(TAG, " Shaping: %s", shaping_lut[this->shaping_ >> 5]); + static const char *shaping_lut[4] = {"NONE", "CUTOFF_BR_X_1", "CUTOFF_BR_X_2", "ERROR"}; + ESP_LOGCONFIG(TAG, " Shaping: %s", shaping_lut[this->shaping_ >> SHAPING_SHIFT]); } ESP_LOGCONFIG(TAG, " PA Pin: %s", this->pa_pin_ == PA_PIN_BOOST ? "BOOST" : "RFO"); ESP_LOGCONFIG(TAG, " PA Power: %" PRIu32 " dBm", this->pa_power_); diff --git a/esphome/components/sx127x/sx127x.h b/esphome/components/sx127x/sx127x.h index b01fbcac96..f8809b3e0b 100644 --- a/esphome/components/sx127x/sx127x.h +++ b/esphome/components/sx127x/sx127x.h @@ -183,7 +183,8 @@ enum SX127xPaRamp : uint8_t { GAUSSIAN_BT_0_3 = 0x60, GAUSSIAN_BT_0_5 = 0x40, GAUSSIAN_BT_1_0 = 0x20, - NO_SHAPING = 0x00, + SHAPING_NONE = 0x00, + SHAPING_SHIFT = 0x05, PA_RAMP_10 = 0x0F, PA_RAMP_12 = 0x0E, PA_RAMP_15 = 0x0D, @@ -206,6 +207,7 @@ struct SX127xStore { static void gpio_intr(SX127xStore *arg); volatile uint32_t dio0_micros{0}; volatile bool dio0_irq{false}; + volatile bool dio2_set{false}; volatile bool dio2_toggle{false}; ISRInternalGPIOPin dio2_pin; };