mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 17:27:59 +01:00
baud rate
This commit is contained in:
parent
def2be4b83
commit
8681a5b302
4 changed files with 155 additions and 102 deletions
|
@ -7,6 +7,7 @@ from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option
|
|||
# from esphome.components.wifi import wifi_has_sta # uncomment after PR#4091 merged
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_BAUD_RATE,
|
||||
CONF_DEBUG,
|
||||
CONF_ENABLE_ON_BOOT,
|
||||
CONF_ID,
|
||||
|
@ -79,6 +80,7 @@ CONFIG_SCHEMA = cv.All(
|
|||
cv.GenerateID(CONF_ID): cv.declare_id(ModemComponent),
|
||||
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_schema,
|
||||
cv.Required(CONF_RX_PIN): pins.internal_gpio_output_pin_schema,
|
||||
cv.Optional(CONF_BAUD_RATE): cv.positive_int,
|
||||
cv.Required(CONF_MODEL): cv.one_of(*MODEM_MODELS, upper=True),
|
||||
cv.Required(CONF_APN): cv.string,
|
||||
cv.Optional(CONF_STATUS_PIN): pins.gpio_input_pin_schema,
|
||||
|
@ -166,8 +168,8 @@ async def to_code(config):
|
|||
# If Uart queue full message ( A7672 ), those config option might be changed
|
||||
# https://github.com/espressif/esp-protocols/issues/272#issuecomment-1558682967
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD", True)
|
||||
add_idf_sdkconfig_option("ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED", True)
|
||||
add_idf_sdkconfig_option("ESP_MODEM_CMUX_USE_SHORT_PAYLOADS_ONLY", False)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_MODEM_CMUX_USE_SHORT_PAYLOADS_ONLY", False)
|
||||
|
||||
cg.add_define("USE_MODEM")
|
||||
|
||||
|
@ -218,6 +220,9 @@ async def to_code(config):
|
|||
rx_pin = await cg.gpio_pin_expression(config[CONF_RX_PIN])
|
||||
cg.add(var.set_rx_pin(rx_pin))
|
||||
|
||||
if baud_rate := config.get(CONF_BAUD_RATE, None):
|
||||
cg.add(var.set_baud_rate(baud_rate))
|
||||
|
||||
if status_pin := config.get(CONF_STATUS_PIN, None):
|
||||
pin = await cg.gpio_pin_expression(status_pin)
|
||||
cg.add(var.set_status_pin(pin))
|
||||
|
|
|
@ -48,11 +48,7 @@ ModemComponent::ModemComponent() {
|
|||
global_modem_component = this;
|
||||
}
|
||||
|
||||
void ModemComponent::enable_debug() {
|
||||
esp_log_level_set("command_lib", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("CMUX", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("CMUX Received", ESP_LOG_VERBOSE);
|
||||
}
|
||||
void ModemComponent::enable_debug() { esp_log_level_set("command_lib", ESP_LOG_VERBOSE); }
|
||||
|
||||
bool ModemComponent::is_modem_connected(bool verbose) {
|
||||
float rssi, ber;
|
||||
|
@ -98,6 +94,8 @@ AtCommandResult ModemComponent::get_imei() {
|
|||
} else {
|
||||
at_command_result.success = false;
|
||||
}
|
||||
ESP_LOGV(TAG, "imei: %s (status: %s)", at_command_result.c_str(),
|
||||
command_result_to_string(at_command_result.esp_modem_command_result).c_str());
|
||||
return at_command_result;
|
||||
}
|
||||
|
||||
|
@ -114,25 +112,28 @@ bool ModemComponent::get_power_status() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool ModemComponent::sync() {
|
||||
this->internal_state_.modem_synced = this->get_imei();
|
||||
if (this->internal_state_.modem_synced)
|
||||
this->internal_state_.powered_on = true;
|
||||
return this->internal_state_.modem_synced;
|
||||
}
|
||||
|
||||
bool ModemComponent::modem_ready(bool force_check) {
|
||||
// check if the modem is ready to answer AT commands
|
||||
// We first try to check flags, and then really send an AT command if force_check
|
||||
|
||||
if (!this->dce)
|
||||
return false;
|
||||
if (!this->internal_state_.modem_synced)
|
||||
return false;
|
||||
if (!this->cmux_ && this->internal_state_.connected)
|
||||
return false;
|
||||
if (!this->internal_state_.powered_on)
|
||||
return false;
|
||||
#ifdef USE_MODEM_POWER
|
||||
if (this->internal_state_.power_transition)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (force_check) {
|
||||
if (this->get_imei()) {
|
||||
if (this->sync()) {
|
||||
// we are sure that the modem is on
|
||||
this->internal_state_.powered_on = true;
|
||||
return true;
|
||||
|
@ -142,8 +143,6 @@ bool ModemComponent::modem_ready(bool force_check) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ModemComponent::modem_ready() { return this->modem_ready(false); }
|
||||
|
||||
void ModemComponent::enable() {
|
||||
ESP_LOGD(TAG, "Enabling modem");
|
||||
if (this->component_state_ == ModemComponentState::DISABLED) {
|
||||
|
@ -259,7 +258,7 @@ void ModemComponent::setup() {
|
|||
nullptr);
|
||||
ESPHL_ERROR_CHECK(err, "IP event handler register error");
|
||||
|
||||
this->modem_lazy_init_();
|
||||
this->modem_create_dce_dte_(); // real init will be done by enable
|
||||
|
||||
ESP_LOGV(TAG, "Setup finished");
|
||||
}
|
||||
|
@ -291,7 +290,7 @@ void ModemComponent::loop() {
|
|||
break;
|
||||
case ModemPowerState::TONUART:
|
||||
ESP_LOGD(TAG, "TONUART check sync");
|
||||
if (!this->modem_sync_()) {
|
||||
if (!this->modem_init_()) {
|
||||
ESP_LOGE(TAG, "Unable to power on the modem");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Modem powered ON");
|
||||
|
@ -329,8 +328,8 @@ void ModemComponent::loop() {
|
|||
if (this->internal_state_.starting) {
|
||||
ESP_LOGW(TAG, "Modem not responding, resetting...");
|
||||
this->internal_state_.connected = false;
|
||||
// this->modem_lazy_init_();
|
||||
if (!this->modem_sync_()) {
|
||||
// this->modem_create_dce_dte_();
|
||||
if (!this->modem_init_()) {
|
||||
ESP_LOGE(TAG, "Unable to recover modem");
|
||||
} else {
|
||||
this->component_state_ = ModemComponentState::DISCONNECTED;
|
||||
|
@ -345,7 +344,7 @@ void ModemComponent::loop() {
|
|||
this->poweron_();
|
||||
break;
|
||||
} else if (!this->internal_state_.modem_synced) {
|
||||
if (!this->modem_sync_()) {
|
||||
if (!this->modem_init_()) {
|
||||
this->component_state_ = ModemComponentState::NOT_RESPONDING;
|
||||
}
|
||||
}
|
||||
|
@ -443,15 +442,12 @@ void ModemComponent::loop() {
|
|||
}
|
||||
}
|
||||
|
||||
void ModemComponent::modem_lazy_init_() {
|
||||
// destroy previous dte/dce, and recreate them.
|
||||
void ModemComponent::modem_create_dce_dte_(int baud_rate) {
|
||||
// create or recreate dte and dce.
|
||||
// no communication is done with the modem.
|
||||
|
||||
this->internal_state_.modem_synced = false;
|
||||
|
||||
this->dte_.reset();
|
||||
this->dce.reset();
|
||||
|
||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
|
||||
dte_config.uart_config.tx_io_num = this->tx_pin_->get_pin();
|
||||
|
@ -459,10 +455,16 @@ void ModemComponent::modem_lazy_init_() {
|
|||
dte_config.uart_config.rx_buffer_size = this->uart_rx_buffer_size_;
|
||||
dte_config.uart_config.tx_buffer_size = this->uart_tx_buffer_size_;
|
||||
dte_config.uart_config.event_queue_size = this->uart_event_queue_size_;
|
||||
if (baud_rate != 0) {
|
||||
dte_config.uart_config.baud_rate = baud_rate;
|
||||
this->internal_state_.baud_rate_changed = true;
|
||||
}
|
||||
dte_config.task_stack_size = this->uart_event_task_stack_size_;
|
||||
dte_config.task_priority = this->uart_event_task_priority_;
|
||||
dte_config.dte_buffer_size = this->uart_rx_buffer_size_ / 2;
|
||||
|
||||
this->dce.reset();
|
||||
this->dte_.reset();
|
||||
this->dte_ = create_uart_dte(&dte_config);
|
||||
|
||||
if (!this->dte_->set_mode(modem_mode::COMMAND_MODE)) {
|
||||
|
@ -497,69 +499,99 @@ void ModemComponent::modem_lazy_init_() {
|
|||
ESP_LOGV(TAG, "DTE and CDE created");
|
||||
}
|
||||
|
||||
bool ModemComponent::modem_sync_() {
|
||||
// force command mode, check sim, and send init_at commands
|
||||
// close cmux/data if needed, and may reboot the modem.
|
||||
bool ModemComponent::modem_preinit_() {
|
||||
// init the modem to get command mode.
|
||||
// if baud_rate != 0, will also set the baud rate.
|
||||
|
||||
uint32_t start_ms = millis();
|
||||
uint32_t elapsed_ms;
|
||||
std::string result;
|
||||
// std::string result;
|
||||
|
||||
ESP_LOGV(TAG, "Checking if the modem is synced...");
|
||||
ESP_LOGV(TAG, "Checking if the modem is reachable...");
|
||||
|
||||
this->flush_uart_();
|
||||
|
||||
bool status = this->get_imei();
|
||||
if (!status) {
|
||||
bool success = this->sync();
|
||||
if (!success) {
|
||||
// the modem is not responding. possible causes are:
|
||||
// - warm reboot, it's still in data or cmux mode.
|
||||
// - has a non default baud rate
|
||||
// - power off
|
||||
|
||||
uint32_t start_ms = millis();
|
||||
uint32_t elapsed_ms;
|
||||
|
||||
// Try to exit CMUX_MANUAL_DATA or DATA_MODE, if any
|
||||
ESP_LOGD(TAG, "Connecting to the the modem...");
|
||||
watchdog::WatchdogManager wdt(30000);
|
||||
// huge watchdog, because some commands are blocking for a very long time.
|
||||
watchdog::WatchdogManager wdt(60000);
|
||||
|
||||
auto command_mode = [this]() -> bool {
|
||||
ESP_LOGVV(TAG, "trying command mode");
|
||||
ESP_LOGV(TAG, "trying command mode");
|
||||
this->dce->set_mode(modem_mode::UNDEF);
|
||||
return this->dce->set_mode(modem_mode::COMMAND_MODE) && this->get_imei();
|
||||
return this->dce->set_mode(modem_mode::COMMAND_MODE) && this->sync();
|
||||
};
|
||||
|
||||
auto cmux_command_mode = [this]() -> bool {
|
||||
ESP_LOGVV(TAG, "trying cmux command mode");
|
||||
ESP_LOGV(TAG, "trying cmux command mode");
|
||||
return this->dce->set_mode(modem_mode::CMUX_MANUAL_MODE) &&
|
||||
this->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) && this->get_imei();
|
||||
this->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) && this->sync();
|
||||
};
|
||||
|
||||
// The cmux state is supposed to be the same before the reboot. But if it has changed (new firwmare), we will try
|
||||
// to fallback to inverted cmux state.
|
||||
if (this->cmux_) {
|
||||
status = cmux_command_mode() || (command_mode() && cmux_command_mode());
|
||||
success = cmux_command_mode() || (command_mode() && cmux_command_mode());
|
||||
} else {
|
||||
status = command_mode() || (cmux_command_mode() && command_mode());
|
||||
success = command_mode() || (cmux_command_mode() && command_mode());
|
||||
}
|
||||
|
||||
elapsed_ms = millis() - start_ms;
|
||||
|
||||
if (!status) {
|
||||
ESP_LOGW(TAG, "modem not responding after %" PRIu32 "ms.", elapsed_ms);
|
||||
// assume the modem is OFF
|
||||
this->internal_state_.powered_on = false;
|
||||
} else {
|
||||
if (success) {
|
||||
ESP_LOGD(TAG, "Connected to the modem in %" PRIu32 "ms", elapsed_ms);
|
||||
this->internal_state_.powered_on = true;
|
||||
}
|
||||
} else if ((this->baud_rate_ != 0) && !this->internal_state_.baud_rate_changed) {
|
||||
ESP_LOGD(TAG, "Failed to connected to the modem in %" PRIu32 "ms", elapsed_ms);
|
||||
ESP_LOGD(TAG, "Retrying with baud rate %d", this->baud_rate_);
|
||||
this->modem_create_dce_dte_(this->baud_rate_);
|
||||
return this->modem_preinit_(); // recursive call, but only 1 depth
|
||||
} else {
|
||||
// modem responded without need to recover command mode
|
||||
ESP_LOGD(TAG, "Modem already synced");
|
||||
this->internal_state_.powered_on = true;
|
||||
ESP_LOGE(TAG, "Fatal: modem not responding during init");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (status && !this->internal_state_.modem_synced) {
|
||||
this->internal_state_.modem_synced = true;
|
||||
// modem synced
|
||||
|
||||
// First time the modem is synced, or modem recovered
|
||||
App.feed_wdt();
|
||||
watchdog::WatchdogManager wdt(30000);
|
||||
delay(2000); // NOLINT
|
||||
if (!this->get_imei()) {
|
||||
ESP_LOGW(TAG, "Unable to sync modem");
|
||||
if ((this->baud_rate_ != 0) && !this->internal_state_.baud_rate_changed) {
|
||||
ESP_LOGD(TAG, "Setting baud rate: %d", this->baud_rate_);
|
||||
this->dce->set_baud(this->baud_rate_);
|
||||
delay(1000);
|
||||
this->flush_uart_();
|
||||
// need to recreate dte/dce with new baud rate
|
||||
this->modem_create_dce_dte_(this->baud_rate_);
|
||||
this->flush_uart_();
|
||||
if (this->sync()) {
|
||||
ESP_LOGI(TAG, "Modem baud rate set to %d", this->baud_rate_);
|
||||
success = true;
|
||||
} else {
|
||||
// not able to switch to new baud rate. reset to default
|
||||
this->internal_state_.baud_rate_changed = false;
|
||||
this->modem_create_dce_dte_();
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
this->internal_state_.modem_synced = success;
|
||||
this->internal_state_.powered_on = success;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ModemComponent::modem_init_() {
|
||||
// force command mode, check sim, and send init_at commands
|
||||
// close cmux/data if needed, and may reboot the modem.
|
||||
|
||||
bool success = this->modem_preinit_() && this->sync();
|
||||
|
||||
if (!success) {
|
||||
ESP_LOGE(TAG, "Fatal: modem not responding");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -567,9 +599,8 @@ bool ModemComponent::modem_sync_() {
|
|||
|
||||
if (!this->pin_code_.empty()) {
|
||||
if (!this->prepare_sim_()) {
|
||||
// fatal error
|
||||
this->disable();
|
||||
status = false;
|
||||
ESP_LOGE(TAG, "Fatal: Sim error");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No pin_code, so no pin check");
|
||||
|
@ -579,22 +610,21 @@ bool ModemComponent::modem_sync_() {
|
|||
std::string result;
|
||||
ESPMODEM_ERROR_CHECK(this->dce->get_module_name(result), "get_module_name");
|
||||
ESP_LOGI(TAG, " Module name: %s", result.c_str());
|
||||
|
||||
success = this->sync();
|
||||
|
||||
if (!success) {
|
||||
ESP_LOGE(TAG, "Fatal: unable to init modem");
|
||||
}
|
||||
|
||||
this->internal_state_.modem_synced = status;
|
||||
|
||||
ESP_LOGVV(TAG, "Sync end status: %d", this->internal_state_.modem_synced);
|
||||
|
||||
return status;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ModemComponent::prepare_sim_() {
|
||||
command_result modem_status;
|
||||
|
||||
std::string output;
|
||||
|
||||
// this->dce->read_pin(pin_ok) // not used, because we can't know the cause of the error.
|
||||
modem_status = this->dce->command(
|
||||
this->dce->command(
|
||||
"AT+CPIN?\r",
|
||||
[&](uint8_t *data, size_t len) {
|
||||
output.assign(reinterpret_cast<char *>(data), len);
|
||||
|
@ -605,11 +635,11 @@ bool ModemComponent::prepare_sim_() {
|
|||
|
||||
ESP_LOGD(TAG, "SIM: %s", output.c_str());
|
||||
|
||||
if (output.find("+CPIN: READY") != std::string::npos) {
|
||||
if ((output.find("+CPIN: READY") != std::string::npos) || (output.find("+CPIN: SIM PIN") != std::string::npos)) {
|
||||
return true; // pin not needed or already unlocked
|
||||
} else {
|
||||
if (output.find("SIM not inserted") != std::string::npos) {
|
||||
this->abort_("Sim card not inserted.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,14 +655,22 @@ void ModemComponent::send_init_at_() {
|
|||
// send initial AT commands from yaml
|
||||
for (const auto &cmd : this->init_at_commands_) {
|
||||
App.feed_wdt();
|
||||
auto at_command_result = this->send_at(cmd);
|
||||
if (!at_command_result) {
|
||||
ESP_LOGE(TAG, "Error while executing 'init_at' '%s' command", cmd.c_str());
|
||||
} else {
|
||||
ESP_LOGI(TAG, "'init_at' '%s' output: %s", cmd.c_str(), at_command_result.output.c_str());
|
||||
}
|
||||
delay(2000); // NOLINT
|
||||
|
||||
std::string output;
|
||||
|
||||
ESPMODEM_ERROR_CHECK(this->dce->command(
|
||||
cmd + "\r",
|
||||
[&](uint8_t *data, size_t len) {
|
||||
output.assign(reinterpret_cast<char *>(data), len);
|
||||
std::replace(output.begin(), output.end(), '\n', ' ');
|
||||
return command_result::OK;
|
||||
},
|
||||
2000),
|
||||
"init_at");
|
||||
|
||||
ESP_LOGI(TAG, "init_at %s: %s", cmd.c_str(), output.c_str());
|
||||
}
|
||||
this->flush_uart_();
|
||||
}
|
||||
|
||||
bool ModemComponent::is_network_attached_() {
|
||||
|
@ -739,7 +777,7 @@ void ModemComponent::poweroff_() {
|
|||
|
||||
void ModemComponent::abort_(const std::string &message) {
|
||||
ESP_LOGE(TAG, "Aborting: %s", message.c_str());
|
||||
this->send_at("AT+CFUN=1,1");
|
||||
// this->send_at("AT+CFUN=1,1");
|
||||
App.reboot();
|
||||
}
|
||||
|
||||
|
@ -767,18 +805,21 @@ void ModemComponent::dump_connect_params_() {
|
|||
|
||||
bool ModemComponent::flush_uart_() {
|
||||
size_t cleaned = 0;
|
||||
|
||||
std::string output;
|
||||
this->dce->command(
|
||||
"",
|
||||
[&](uint8_t *data, size_t len) {
|
||||
cleaned = len;
|
||||
output.assign(reinterpret_cast<char *>(data), len);
|
||||
std::replace(output.begin(), output.end(), '\n', ' ');
|
||||
return command_result::OK;
|
||||
},
|
||||
1000) == command_result::OK;
|
||||
2000);
|
||||
|
||||
if (cleaned != 0) {
|
||||
ESP_LOGW(TAG, "Cleaned %d modem buffer data", cleaned);
|
||||
ESP_LOGW(TAG, "Cleaned %d modem buffer data: %s", cleaned, output.c_str());
|
||||
}
|
||||
return cleaned != 0;
|
||||
}
|
||||
|
||||
const char *AtCommandResult::c_str() const {
|
||||
|
|
|
@ -58,6 +58,7 @@ class ModemComponent : public Component {
|
|||
void set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
|
||||
void set_rx_pin(InternalGPIOPin *rx_pin) { this->rx_pin_ = rx_pin; }
|
||||
void set_tx_pin(InternalGPIOPin *tx_pin) { this->tx_pin_ = tx_pin; }
|
||||
void set_baud_rate(int baud_rate) { this->baud_rate_ = baud_rate; }
|
||||
void set_model(const std::string &model) { this->model_ = model; }
|
||||
void set_power_pin(GPIOPin *power_pin) { this->power_pin_ = power_pin; }
|
||||
void set_power_ton(int ton) { this->power_ton_ = ton; }
|
||||
|
@ -78,7 +79,8 @@ class ModemComponent : public Component {
|
|||
AtCommandResult send_at(const std::string &cmd, uint32_t timeout);
|
||||
AtCommandResult get_imei();
|
||||
bool get_power_status();
|
||||
bool modem_ready();
|
||||
bool sync();
|
||||
bool modem_ready() { return this->modem_ready(false); }
|
||||
bool modem_ready(bool force_check);
|
||||
void enable();
|
||||
void disable();
|
||||
|
@ -105,8 +107,10 @@ class ModemComponent : public Component {
|
|||
std::unique_ptr<DCE> dce{nullptr};
|
||||
|
||||
protected:
|
||||
void modem_lazy_init_();
|
||||
bool modem_sync_();
|
||||
void modem_create_dce_dte_(int baud_rate);
|
||||
void modem_create_dce_dte_() { this->modem_create_dce_dte_(0); }
|
||||
bool modem_preinit_();
|
||||
bool modem_init_();
|
||||
bool prepare_sim_();
|
||||
void send_init_at_();
|
||||
bool is_network_attached_();
|
||||
|
@ -147,6 +151,7 @@ class ModemComponent : public Component {
|
|||
uint8_t uart_event_task_priority_ = 5; // 3-22
|
||||
uint32_t command_delay_ = 1000; // timeout for AT commands
|
||||
uint32_t reconnect_grace_period_ = 30000; // let some time to mqtt or api to reconnect before retry
|
||||
int baud_rate_ = 0;
|
||||
|
||||
// Changes will trigger user callback
|
||||
ModemComponentState component_state_{ModemComponentState::DISABLED};
|
||||
|
@ -163,7 +168,7 @@ class ModemComponent : public Component {
|
|||
bool enabled{false};
|
||||
bool connected{false};
|
||||
bool got_ipv4_address{false};
|
||||
// true if modem_sync_ was sucessfull
|
||||
// true if modem_init_ was sucessfull
|
||||
bool modem_synced{false};
|
||||
// date start (millis())
|
||||
uint32_t connect_begin;
|
||||
|
@ -175,6 +180,7 @@ class ModemComponent : public Component {
|
|||
ModemPowerState power_state{ModemPowerState::TOFFUART};
|
||||
// ask the modem to reconnect
|
||||
bool reconnect{false};
|
||||
bool baud_rate_changed{false};
|
||||
};
|
||||
InternalState internal_state_;
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ modem:
|
|||
id: atmodem
|
||||
rx_pin: GPIO26
|
||||
tx_pin: GPIO27
|
||||
baud_rate: 115200
|
||||
power_pin:
|
||||
number: GPIO04
|
||||
inverted: True
|
||||
|
|
Loading…
Reference in a new issue