diff --git a/esphome/components/lora/__init__.py b/esphome/components/lora/__init__.py index b193a49e60..f63bf9c8bd 100644 --- a/esphome/components/lora/__init__.py +++ b/esphome/components/lora/__init__.py @@ -4,31 +4,21 @@ from esphome import pins from esphome.components import sensor, text_sensor, uart from esphome.const import * +DEPENDENCIES = ["uart"] +MULTI_CONF = True + lora_ns = cg.esphome_ns.namespace("lora") Lora = lora_ns.class_("Lora", cg.Component, uart.UARTDevice) - -DEPENDENCIES = ["uart"] -AUTO_LOAD = ["uart", "sensor", "text_sensor"] - +LoraGPIOPin = lora_ns.class_("LoraGPIOPin", cg.GPIOPin) CONF_PIN_AUX = "pin_aux" CONF_PIN_M0 = "pin_m0" CONF_PIN_M1 = "pin_m1" CONF_LORA_MESSAGE = "lora_message" CONF_LORA_RSSI = "lora_rssi" - +CONF_LORA = "lora" CONFIG_SCHEMA = ( cv.Schema( { - # if you send gps locations over lora, this will be able to read it - cv.Optional(CONF_LATITUDE): sensor.sensor_schema( - unit_of_measurement=UNIT_DEGREES, - accuracy_decimals=6, - ), - # if you send gps locations over lora, this will be able to read it - cv.Optional(CONF_LONGITUDE): sensor.sensor_schema( - unit_of_measurement=UNIT_DEGREES, - accuracy_decimals=6, - ), cv.GenerateID(): cv.declare_id(Lora), # for communication to let us know that we can receive data cv.Required(CONF_PIN_AUX): pins.gpio_input_pin_schema, @@ -54,6 +44,27 @@ CONFIG_SCHEMA = ( ) +def validate_mode(value): + if not (value[CONF_OUTPUT]): + raise cv.Invalid("Mode must be output") + if value[CONF_INPUT] and value[CONF_OUTPUT]: + raise cv.Invalid("Mode must be output") + return value + + +Lora_PIN_SCHEMA = pins.gpio_base_schema( + LoraGPIOPin, + cv.int_range(min=0, max=17), + modes=[CONF_OUTPUT], + mode_validator=validate_mode, + invertable=True, +).extend( + { + cv.Required(CONF_LORA): cv.use_id(Lora), + } +) + + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) @@ -74,3 +85,17 @@ async def to_code(config): if CONF_LORA_RSSI in config: sens = await sensor.new_sensor(config[CONF_LORA_RSSI]) cg.add(var.set_rssi_sensor(sens)) + + +@pins.PIN_SCHEMA_REGISTRY.register(CONF_LORA, Lora_PIN_SCHEMA) +async def lora_pin_to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + parent = await cg.get_variable(config[CONF_LORA]) + + cg.add(var.set_parent(parent)) + + num = config[CONF_NUMBER] + cg.add(var.set_pin(num)) + cg.add(var.set_inverted(config[CONF_INVERTED])) + cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) + return var diff --git a/esphome/components/lora/lora.cpp b/esphome/components/lora/lora.cpp index f1721423a0..c7e5a3e10a 100644 --- a/esphome/components/lora/lora.cpp +++ b/esphome/components/lora/lora.cpp @@ -124,7 +124,10 @@ void Lora::dump_config() { LOG_PIN("M0 Pin:", this->pin_m0); LOG_PIN("M1 Pin:", this->pin_m1); }; - +void Lora::digital_write(uint8_t pin, bool value) { + std::string message = str_snprintf("%02x%02x", 12, pin, value); + sendMessage(message); +} bool Lora::sendMessage(std::string message) { uint8_t size = message.length(); char messageFixed[size]; diff --git a/esphome/components/lora/lora.h b/esphome/components/lora/lora.h index 60fa6d40a7..9e41a9a4bb 100644 --- a/esphome/components/lora/lora.h +++ b/esphome/components/lora/lora.h @@ -33,8 +33,12 @@ class Lora : public PollingComponent, public uart::UARTDevice { void loop() override; void dump_config() override; // local - void set_latitude_sensor(sensor::Sensor *latitude_sensor) { latitude_sensor_ = latitude_sensor; } - void set_longitude_sensor(sensor::Sensor *longitude_sensor) { longitude_sensor_ = longitude_sensor; } + /// Helper function to read the value of a pin. + bool digital_read(uint8_t pin); + /// Helper function to write the value of a pin. + void digital_write(uint8_t pin, bool value); + /// Helper function to set the pin mode of a pin. + void pin_mode(uint8_t pin, gpio::Flags flags); void set_message_sensor(text_sensor::TextSensor *s) { message_text_sensor = s; } void set_rssi_sensor(sensor::Sensor *s) { rssi_sensor = s; } void set_pin_aux(GPIOPin *s) { pin_aux = s; } @@ -54,8 +58,6 @@ class Lora : public PollingComponent, public uart::UARTDevice { float latitude_ = -1; float longitude_ = -1; std::string raw_message_; - sensor::Sensor *latitude_sensor_{nullptr}; - sensor::Sensor *longitude_sensor_{nullptr}; text_sensor::TextSensor *message_text_sensor{nullptr}; sensor::Sensor *rssi_sensor{nullptr}; GPIOPin *pin_aux{nullptr}; diff --git a/esphome/components/lora/lora_pin.cpp b/esphome/components/lora/lora_pin.cpp new file mode 100644 index 0000000000..5d93e82fd1 --- /dev/null +++ b/esphome/components/lora/lora_pin.cpp @@ -0,0 +1,22 @@ +#include "lora_pin.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace lora { + +static const char *const TAG = "lora.pin"; +void LoraGPIOPin::setup() { pin_mode(flags_); } +void LoraGPIOPin::pin_mode(gpio::Flags flags) { + if (flags != gpio::FLAG_OUTPUT) { + ESP_LOGD(TAG, "Output only supported"); + } +} +bool LoraGPIOPin::digital_read() { return false; } +void LoraGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } +std::string LoraGPIOPin::dump_summary() const { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%u via Lora", pin_); + return buffer; +} +} // namespace lora +} // namespace esphome diff --git a/esphome/components/lora/lora_pin.h b/esphome/components/lora/lora_pin.h new file mode 100644 index 0000000000..0953f8546e --- /dev/null +++ b/esphome/components/lora/lora_pin.h @@ -0,0 +1,33 @@ +#pragma once + +#include "esphome/core/component.h" +#include "./lora.h" + +#include +#include + +namespace esphome { +namespace lora { + +class LoraGPIOPin : public GPIOPin { + public: + void setup() override; + void pin_mode(gpio::Flags flags) override; + bool digital_read() override; + void digital_write(bool value) override; + std::string dump_summary() const override; + + void set_parent(Lora *parent) { parent_ = parent; } + void set_pin(uint8_t pin) { pin_ = pin; } + void set_inverted(bool inverted) { inverted_ = inverted; } + void set_flags(gpio::Flags flags) { flags_ = flags; } + + protected: + Lora *parent_; + uint8_t pin_; + bool inverted_; + gpio::Flags flags_; +}; + +} // namespace lora +} // namespace esphome diff --git a/esphome/components/lora/switch/__init__.py b/esphome/components/lora/switch/__init__.py deleted file mode 100644 index 8b48f233aa..0000000000 --- a/esphome/components/lora/switch/__init__.py +++ /dev/null @@ -1,71 +0,0 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import switch, uart -from esphome.const import CONF_DATA, CONF_SEND_EVERY -from esphome.core import HexInt -from .. import lora_ns - - -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" - ) - - -DEPENDENCIES = ["uart"] - -LoraSwitch = lora_ns.class_("LoraSwitch", switch.Switch, uart.UARTDevice, cg.Component) - -CONF_TURN_OFF = "turn_off" -CONF_TURN_ON = "turn_on" - -CONFIG_SCHEMA = ( - switch.switch_schema(LoraSwitch, block_inverted=True) - .extend( - { - cv.Required(CONF_DATA): cv.Any( - validate_raw_data, - cv.Schema( - { - cv.Optional(CONF_TURN_OFF): validate_raw_data, - cv.Optional(CONF_TURN_ON): validate_raw_data, - } - ), - ), - cv.Optional(CONF_SEND_EVERY): cv.positive_time_period_milliseconds, - }, - ) - .extend(uart.UART_DEVICE_SCHEMA) - .extend(cv.COMPONENT_SCHEMA) -) - - -async def to_code(config): - var = await switch.new_switch(config) - await cg.register_component(var, config) - await uart.register_uart_device(var, config) - - data = config[CONF_DATA] - if isinstance(data, dict): - if data_on := data.get(CONF_TURN_ON): - if isinstance(data_on, bytes): - data_on = [HexInt(x) for x in data_on] - cg.add(var.set_data_on(data_on)) - if data_off := data.get(CONF_TURN_OFF): - if isinstance(data_off, bytes): - data_off = [HexInt(x) for x in data_off] - cg.add(var.set_data_off(data_off)) - else: - data = config[CONF_DATA] - if isinstance(data, bytes): - data = [HexInt(x) for x in data] - cg.add(var.set_data_on(data)) - cg.add(var.set_single_state(True)) - if CONF_SEND_EVERY in config: - cg.add(var.set_send_every(config[CONF_SEND_EVERY])) diff --git a/esphome/components/lora/switch/lora_switch.cpp b/esphome/components/lora/switch/lora_switch.cpp deleted file mode 100644 index a92eb43567..0000000000 --- a/esphome/components/lora/switch/lora_switch.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "lora_switch.h" -#include "esphome/core/log.h" - -namespace esphome { -namespace lora { - -static const char *const TAG = "lora.switch"; - -void LoraSwitch::loop() { - if (this->send_every_) { - const uint32_t now = millis(); - if (now - this->last_transmission_ > this->send_every_) { - this->write_command_(this->state); - this->last_transmission_ = now; - } - } -} - -void LoraSwitch::write_command_(bool state) { - if (state && !this->data_on_.empty()) { - ESP_LOGD(TAG, "'%s': Sending on data...", this->get_name().c_str()); - this->write_array(this->data_on_.data(), this->data_on_.size()); - } - if (!state && !this->data_off_.empty()) { - ESP_LOGD(TAG, "'%s': Sending off data...", this->get_name().c_str()); - this->write_array(this->data_off_.data(), this->data_off_.size()); - } -} - -void LoraSwitch::write_state(bool state) { - if (!this->single_state_) { - this->publish_state(state); - this->write_command_(state); - this->last_transmission_ = millis(); - return; - } - - if (!state) { - this->publish_state(false); - return; - } - - this->publish_state(true); - this->write_command_(true); - - if (this->send_every_ == 0) { - this->publish_state(false); - } else { - this->last_transmission_ = millis(); - } -} - -void LoraSwitch::dump_config() { - LOG_SWITCH("", "UART Switch", this); - if (this->send_every_) { - ESP_LOGCONFIG(TAG, " Send Every: %" PRIu32, this->send_every_); - } -} - -} // namespace lora -} // namespace esphome diff --git a/esphome/components/lora/switch/lora_switch.h b/esphome/components/lora/switch/lora_switch.h deleted file mode 100644 index fc7250b353..0000000000 --- a/esphome/components/lora/switch/lora_switch.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "esphome/core/component.h" -#include "esphome/components/uart/uart.h" -#include "esphome/components/switch/switch.h" - -#include -#include - -namespace esphome { -namespace lora { - -class LoraSwitch : public switch_::Switch, public uart::UARTDevice, public Component { - public: - void loop() override; - - void set_data_on(const std::vector &data) { this->data_on_ = data; } - void set_data_off(const std::vector &data) { this->data_off_ = data; } - void set_send_every(uint32_t send_every) { this->send_every_ = send_every; } - void set_single_state(bool single) { this->single_state_ = single; } - - void dump_config() override; - - protected: - void write_command_(bool state); - void write_state(bool state) override; - std::vector data_on_; - std::vector data_off_; - bool single_state_{false}; - uint32_t send_every_; - uint32_t last_transmission_; -}; - -} // namespace lora -} // namespace esphome