mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 01:34:18 +01:00
user power states
This commit is contained in:
parent
5bc6cd8a17
commit
4b0ae086dc
2 changed files with 115 additions and 70 deletions
|
@ -86,10 +86,15 @@ void ModemComponent::setup() {
|
||||||
|
|
||||||
if (this->power_pin_) {
|
if (this->power_pin_) {
|
||||||
this->power_pin_->setup();
|
this->power_pin_->setup();
|
||||||
|
// as we have a power pin, we assume that the power is off
|
||||||
|
this->powered_on_ = false;
|
||||||
|
|
||||||
if (this->enabled_) {
|
if (this->enabled_) {
|
||||||
this->poweron_();
|
this->poweron_();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// no status pin, we assume that the power is on
|
||||||
|
this->powered_on_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->status_pin_) {
|
if (this->status_pin_) {
|
||||||
|
@ -200,12 +205,14 @@ bool ModemComponent::modem_sync_() {
|
||||||
if (!this->watchdog_)
|
if (!this->watchdog_)
|
||||||
this->watchdog_ = std::make_shared<watchdog::WatchdogManager>(60000);
|
this->watchdog_ = std::make_shared<watchdog::WatchdogManager>(60000);
|
||||||
|
|
||||||
|
uint32_t start_ms = millis();
|
||||||
|
uint32_t elapsed_ms;
|
||||||
|
|
||||||
bool status = this->modem_ready();
|
bool status = this->modem_ready();
|
||||||
if (!status) {
|
if (!status) {
|
||||||
// Try to exit CMUX_MANUAL_DATA or DATA_MODE, if any
|
// Try to exit CMUX_MANUAL_DATA or DATA_MODE, if any
|
||||||
ESP_LOGD(TAG, "Connecting to the the modem...");
|
ESP_LOGD(TAG, "Connecting to the the modem...");
|
||||||
|
|
||||||
uint32_t start_ms = millis();
|
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
auto command_mode_ = [this]() -> bool {
|
auto command_mode_ = [this]() -> bool {
|
||||||
|
@ -228,23 +235,23 @@ bool ModemComponent::modem_sync_() {
|
||||||
status = command_mode_() || (cmux_command_mode_() && command_mode_());
|
status = command_mode_() || (cmux_command_mode_() && command_mode_());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t elapsed_ms = millis() - start_ms;
|
elapsed_ms = millis() - start_ms;
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
ESP_LOGW(TAG, "modem not responding after %" PRIu32 "ms", elapsed_ms);
|
ESP_LOGW(TAG, "modem not responding after %" PRIu32 "ms.", elapsed_ms);
|
||||||
if (this->power_pin_) {
|
this->powered_on_ = false;
|
||||||
ESP_LOGD(TAG, "Trying to power cycle the modem");
|
|
||||||
this->poweroff_();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "Connected to the modem in %" PRIu32 "ms", elapsed_ms);
|
|
||||||
this->send_init_at_();
|
|
||||||
if (!this->prepare_sim_()) {
|
|
||||||
// fatal error
|
|
||||||
this->disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (status) {
|
||||||
|
elapsed_ms = millis() - start_ms;
|
||||||
|
ESP_LOGD(TAG, "Connected to the modem in %" PRIu32 "ms", elapsed_ms);
|
||||||
|
this->send_init_at_();
|
||||||
|
if (!this->prepare_sim_()) {
|
||||||
|
// fatal error
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,12 +367,64 @@ void ModemComponent::loop() {
|
||||||
static uint8_t network_attach_retry = 10;
|
static uint8_t network_attach_retry = 10;
|
||||||
static uint8_t ip_lost_retries = 10;
|
static uint8_t ip_lost_retries = 10;
|
||||||
|
|
||||||
if (this->power_transition_ || (millis() < next_loop_millis)) {
|
if ((millis() < next_loop_millis)) {
|
||||||
// No loop on power transition, or if some commands need some delay
|
// some commands need some delay
|
||||||
yield();
|
yield();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MODEM_POWER
|
||||||
|
if (this->power_transition_) {
|
||||||
|
if (!this->watchdog_)
|
||||||
|
this->watchdog_ = std::make_shared<watchdog::WatchdogManager>(60000);
|
||||||
|
|
||||||
|
// A power state is used to handle long tonuart/toffuart delay
|
||||||
|
switch (this->power_state_) {
|
||||||
|
case ModemPowerState::TON:
|
||||||
|
this->power_pin_->digital_write(false);
|
||||||
|
delay(USE_MODEM_POWER_TON);
|
||||||
|
this->power_pin_->digital_write(true);
|
||||||
|
next_loop_millis = millis() + USE_MODEM_POWER_TONUART; // delay for next loop
|
||||||
|
this->power_state_ = ModemPowerState::TONUART;
|
||||||
|
ESP_LOGD(TAG, "Will check that the modem is on in %.1fs...", float(USE_MODEM_POWER_TONUART) / 1000);
|
||||||
|
break;
|
||||||
|
case ModemPowerState::TONUART:
|
||||||
|
this->power_transition_ = false;
|
||||||
|
if (!this->modem_sync_()) {
|
||||||
|
ESP_LOGE(TAG, "Unable to power on the modem");
|
||||||
|
this->powered_on_ = false;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Modem powered ON");
|
||||||
|
this->powered_on_ = true;
|
||||||
|
this->watchdog_.reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ModemPowerState::TOFF:
|
||||||
|
delay(10);
|
||||||
|
this->power_pin_->digital_write(false);
|
||||||
|
delay(USE_MODEM_POWER_TOFF);
|
||||||
|
this->power_pin_->digital_write(true);
|
||||||
|
this->power_state_ = ModemPowerState::TOFFUART;
|
||||||
|
ESP_LOGD(TAG, "Will check that the modem is off in %.1fs...", float(USE_MODEM_POWER_TOFFUART) / 1000);
|
||||||
|
next_loop_millis = millis() + USE_MODEM_POWER_TOFFUART; // delay for next loop
|
||||||
|
break;
|
||||||
|
case ModemPowerState::TOFFUART:
|
||||||
|
this->power_transition_ = false;
|
||||||
|
if (this->modem_ready()) {
|
||||||
|
ESP_LOGE(TAG, "Unable to power off the modem");
|
||||||
|
this->powered_on_ = true;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Modem powered OFF");
|
||||||
|
this->powered_on_ = false;
|
||||||
|
this->watchdog_.reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // USE_MODEM_POWER
|
||||||
|
|
||||||
switch (this->state_) {
|
switch (this->state_) {
|
||||||
case ModemComponentState::NOT_RESPONDING:
|
case ModemComponentState::NOT_RESPONDING:
|
||||||
if (this->start_) {
|
if (this->start_) {
|
||||||
|
@ -373,10 +432,10 @@ void ModemComponent::loop() {
|
||||||
ESP_LOGI(TAG, "Modem recovered");
|
ESP_LOGI(TAG, "Modem recovered");
|
||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
this->state_ = ModemComponentState::DISCONNECTED;
|
this->state_ = ModemComponentState::DISCONNECTED;
|
||||||
|
last_state = this->state_; // disable on_disconnect cb
|
||||||
} else {
|
} else {
|
||||||
if (!this->get_power_status()) {
|
if (!this->powered_on_) {
|
||||||
// Modem is OFF. If poweron is needed, disconnect state will handle it.
|
this->poweron_();
|
||||||
this->state_ = ModemComponentState::DISCONNECTED;
|
|
||||||
} else if (this->not_responding_cb_) {
|
} else if (this->not_responding_cb_) {
|
||||||
if (!this->not_responding_cb_->is_action_running()) {
|
if (!this->not_responding_cb_->is_action_running()) {
|
||||||
ESP_LOGD(TAG, "Calling 'on_not_responding' callback");
|
ESP_LOGD(TAG, "Calling 'on_not_responding' callback");
|
||||||
|
@ -392,6 +451,14 @@ void ModemComponent::loop() {
|
||||||
// disconnected, want to connect
|
// disconnected, want to connect
|
||||||
case ModemComponentState::DISCONNECTED:
|
case ModemComponentState::DISCONNECTED:
|
||||||
if (this->enabled_) {
|
if (this->enabled_) {
|
||||||
|
if (last_state == ModemComponentState::DISABLED) {
|
||||||
|
last_state = this->state_; // disable on_disconnect cb
|
||||||
|
}
|
||||||
|
if (!this->powered_on_) {
|
||||||
|
this->poweron_();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->start_) {
|
if (this->start_) {
|
||||||
if (connecting) {
|
if (connecting) {
|
||||||
if (this->connected_) {
|
if (this->connected_) {
|
||||||
|
@ -503,9 +570,11 @@ void ModemComponent::loop() {
|
||||||
case ModemComponentState::DISABLED:
|
case ModemComponentState::DISABLED:
|
||||||
if (this->enabled_) {
|
if (this->enabled_) {
|
||||||
this->state_ = ModemComponentState::DISCONNECTED;
|
this->state_ = ModemComponentState::DISCONNECTED;
|
||||||
} // else if (this->get_power_status()) { // FIXME long time in loop because of get_power_status
|
last_state = this->state_; // disable on_disconnect cb
|
||||||
// this->poweroff_();
|
ESP_LOGE(TAG, "here");
|
||||||
//}
|
} else if (this->powered_on_) {
|
||||||
|
this->poweroff_();
|
||||||
|
}
|
||||||
next_loop_millis = millis() + 2000; // delay for next loop
|
next_loop_millis = millis() + 2000; // delay for next loop
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -551,30 +620,9 @@ bool ModemComponent::get_power_status() {
|
||||||
|
|
||||||
void ModemComponent::poweron_() {
|
void ModemComponent::poweron_() {
|
||||||
#ifdef USE_MODEM_POWER
|
#ifdef USE_MODEM_POWER
|
||||||
if (this->power_pin_) {
|
this->power_state_ = ModemPowerState::TON;
|
||||||
App.feed_wdt();
|
this->power_transition_ = true;
|
||||||
ESP_LOGV(TAG, "Powering up modem with power_pin...");
|
return;
|
||||||
this->power_transition_ = true;
|
|
||||||
this->power_pin_->digital_write(false);
|
|
||||||
delay(USE_MODEM_POWER_TON);
|
|
||||||
this->power_pin_->digital_write(true);
|
|
||||||
// use a timout for long wait delay
|
|
||||||
ESP_LOGD(TAG, "Will check that the modem is on in %.1fs...", float(USE_MODEM_POWER_TONUART) / 1000);
|
|
||||||
this->set_timeout("wait_poweron", USE_MODEM_POWER_TONUART, [this]() {
|
|
||||||
// TODO: check modem is able to respond
|
|
||||||
// ESP_LOGD(TAG, "DTE/DCE init after poweron");
|
|
||||||
// this->create_dte_dce_();
|
|
||||||
delay(500); // NOLINT
|
|
||||||
App.feed_wdt();
|
|
||||||
if (!this->modem_ready()) {
|
|
||||||
ESP_LOGE(TAG, "Unable to power on the modem");
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "Modem ready after power ON");
|
|
||||||
}
|
|
||||||
this->power_transition_ = false;
|
|
||||||
yield();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (this->modem_ready()) {
|
if (this->modem_ready()) {
|
||||||
ESP_LOGV(TAG, "Modem is already ON");
|
ESP_LOGV(TAG, "Modem is already ON");
|
||||||
|
@ -586,28 +634,9 @@ void ModemComponent::poweron_() {
|
||||||
|
|
||||||
void ModemComponent::poweroff_() {
|
void ModemComponent::poweroff_() {
|
||||||
#ifdef USE_MODEM_POWER
|
#ifdef USE_MODEM_POWER
|
||||||
if (this->power_pin_) {
|
this->power_state_ = ModemPowerState::TOFF;
|
||||||
ESP_LOGV(TAG, "Powering off modem with power pin...");
|
this->power_transition_ = true;
|
||||||
App.feed_wdt();
|
return;
|
||||||
this->power_transition_ = true;
|
|
||||||
// watchdog::WatchdogManager wdt(60000);
|
|
||||||
// this->power_pin_->digital_write(true);
|
|
||||||
delay(10);
|
|
||||||
this->power_pin_->digital_write(false);
|
|
||||||
delay(USE_MODEM_POWER_TOFF);
|
|
||||||
this->power_pin_->digital_write(true);
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Will check that the modem is off in %.1fs...", float(USE_MODEM_POWER_TOFFUART) / 1000);
|
|
||||||
this->set_timeout("wait_poweroff", USE_MODEM_POWER_TOFFUART, [this]() {
|
|
||||||
if (this->modem_ready()) {
|
|
||||||
ESP_LOGE(TAG, "Unable to power off the modem");
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "Modem OFF");
|
|
||||||
}
|
|
||||||
|
|
||||||
this->power_transition_ = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif // USE_MODEM_POWER
|
#endif // USE_MODEM_POWER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,7 +730,12 @@ bool ModemComponent::get_imei(std::string &result) {
|
||||||
bool ModemComponent::modem_ready() {
|
bool ModemComponent::modem_ready() {
|
||||||
// check if the modem is ready to answer AT commands
|
// check if the modem is ready to answer AT commands
|
||||||
std::string imei;
|
std::string imei;
|
||||||
return this->get_imei(imei);
|
if (this->get_imei(imei)) {
|
||||||
|
// we are sure that the modem is on
|
||||||
|
this->powered_on_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModemComponent::add_on_state_callback(std::function<void(ModemComponentState)> &&callback) {
|
void ModemComponent::add_on_state_callback(std::function<void(ModemComponentState)> &&callback) {
|
||||||
|
|
|
@ -38,6 +38,13 @@ enum class ModemComponentState {
|
||||||
DISABLED,
|
DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ModemPowerState {
|
||||||
|
TON,
|
||||||
|
TONUART,
|
||||||
|
TOFF,
|
||||||
|
TOFFUART,
|
||||||
|
};
|
||||||
|
|
||||||
class ModemComponent : public Component {
|
class ModemComponent : public Component {
|
||||||
public:
|
public:
|
||||||
ModemComponent();
|
ModemComponent();
|
||||||
|
@ -112,7 +119,11 @@ class ModemComponent : public Component {
|
||||||
// timeout for AT commands
|
// timeout for AT commands
|
||||||
uint32_t command_delay_ = 500;
|
uint32_t command_delay_ = 500;
|
||||||
// Will be true when power transitionning
|
// Will be true when power transitionning
|
||||||
bool power_transition_ = false;
|
bool power_transition_{false};
|
||||||
|
// guess power state
|
||||||
|
bool powered_on_{false};
|
||||||
|
// states for triggering on/off signals
|
||||||
|
ModemPowerState power_state_{ModemPowerState::TOFFUART};
|
||||||
// separate handler for `on_not_responding` (we want to know when it's ended)
|
// separate handler for `on_not_responding` (we want to know when it's ended)
|
||||||
Trigger<> *not_responding_cb_{nullptr};
|
Trigger<> *not_responding_cb_{nullptr};
|
||||||
CallbackManager<void(ModemComponentState)> on_state_callback_;
|
CallbackManager<void(ModemComponentState)> on_state_callback_;
|
||||||
|
|
Loading…
Reference in a new issue