diff --git a/esphome/components/modem/modem_component.cpp b/esphome/components/modem/modem_component.cpp index 3147f1b6df..e1616b4eec 100644 --- a/esphome/components/modem/modem_component.cpp +++ b/esphome/components/modem/modem_component.cpp @@ -120,6 +120,10 @@ void ModemComponent::setup() { } this->reset_(); + // At boot time, if the modem power is up, but the modem is not ready, it is probably still in cmux mode + if (this->enabled_ && this->get_power_status() && !this->modem_ready()) { + this->exit_cmux_(); + } ESP_LOGV(TAG, "Setup finished"); } @@ -127,6 +131,7 @@ void ModemComponent::setup() { void ModemComponent::reset_() { // destroy previous dte/dce, and recreate them. // destroying them seems to be the only way to have a clear state after hang up, and be able to reconnect. + // if the modem was previously in cmux mode, this->exit_cmux_(), will be needed after. this->dte_.reset(); this->dce.reset(); @@ -186,21 +191,6 @@ void ModemComponent::reset_() { } else { ESP_LOGI(TAG, "not set_flow_control, because 2-wire mode active."); } - - if (this->enabled_ && this->get_power_status() && !this->modem_ready()) { - // if the esp has rebooted, but the modem not, it is still in cmux mode - // So we close cmux. - // The drawback is that if the modem is poweroff, those commands will take some time to execute. - Watchdog wdt(60); - this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_MODE); - this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_COMMAND); - this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_EXIT); - if (!this->modem_ready()) { - ESP_LOGE(TAG, "Modem still not ready after reset"); - } else { - ESP_LOGD(TAG, "Modem exited previous CMUX session"); - } - } } bool ModemComponent::prepare_sim_() { @@ -379,23 +369,12 @@ void ModemComponent::loop() { ESP_LOGE(TAG, "modem not ready after hang up"); } this->set_timeout("wait_lost_ip", 60000, [this]() { - this->dump_connect_params_(); - this->status_set_error("No lost ip event received"); + this->status_set_error("No lost ip event received. Forcing disconnect state"); this->state_ = ModemComponentState::DISCONNECTED; - // This seems to be the only way to exit CMUX this->reset_(); // reset dce/dte - if (!(this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_MODE) && - this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_EXIT))) { - this->status_set_error("Unable to exit CMUX."); - } - - if (!this->modem_ready()) { - ESP_LOGE(TAG, "modem not ready after reset"); - } - - /////////////////////////// + this->exit_cmux_(); }); } this->start_ = false; @@ -406,14 +385,7 @@ void ModemComponent::loop() { // This seems to be the only way to exit CMUX this->reset_(); // reset dce/dte - if (!(this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_MODE) && - this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_EXIT))) { - this->status_set_error("Unable to exit CMUX."); - } - - if (!this->modem_ready()) { - ESP_LOGE(TAG, "modem not ready after reset"); - } + this->exit_cmux_(); } break; @@ -455,6 +427,25 @@ void ModemComponent::disable() { } } +void ModemComponent::exit_cmux_() { + // This must be called to gain command mode if: + // - if the esp has rebooted, but the modem not, it is still in cmux mode + // - after a dte/dce reset. + // If the modem was previously ready, this will *HANG* de dte, and the modem will be unreachable, with no chances to + // recover it. + // We need this because we are not able to do a simple esp_modem::modem_mode::COMMAND_MODE (this is probably a bug in + // esp_modem) + Watchdog wdt(60); + this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_MODE); + this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_COMMAND); + this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_EXIT); + if (!this->modem_ready()) { + ESP_LOGE(TAG, "Modem still not ready after reset"); + } else { + ESP_LOGD(TAG, "Modem exited previous CMUX session"); + } +} + bool ModemComponent::get_power_status() { if (!this->status_pin_) { ESP_LOGV(TAG, "No status pin, assuming the modem is ON"); diff --git a/esphome/components/modem/modem_component.h b/esphome/components/modem/modem_component.h index 2e5a5f35b6..cb663736ad 100644 --- a/esphome/components/modem/modem_component.h +++ b/esphome/components/modem/modem_component.h @@ -78,6 +78,14 @@ class ModemComponent : public Component { protected: void reset_(); // (re)create dte and dce + bool prepare_sim_(); + void send_init_at_(); + void start_connect_(); + void poweron_(); + void poweroff_(); + static void ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); + void dump_connect_params_(); + void exit_cmux_(); InternalGPIOPin *tx_pin_; InternalGPIOPin *rx_pin_; InternalGPIOPin *status_pin_{nullptr}; @@ -98,19 +106,12 @@ class ModemComponent : public Component { esp_modem_dte_config_t dte_config_; esp_modem_dce_config_t dce_config_; ModemComponentState state_{ModemComponentState::DISABLED}; - bool prepare_sim_(); - void send_init_at_(); - void start_connect_(); - void poweron_(); - void poweroff_(); bool start_{false}; bool enabled_{false}; bool connected_{false}; bool got_ipv4_address_{false}; // date start (millis()) uint32_t connect_begin_; - static void ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); - void dump_connect_params_(); std::string use_address_; // timeout for AT commands uint32_t command_delay_ = 500;