mirror of
https://github.com/esphome/esphome.git
synced 2024-11-24 07:58:09 +01:00
use define for to_code + more conf validation
This commit is contained in:
parent
b8c965b3fc
commit
98ba007de3
3 changed files with 80 additions and 80 deletions
|
@ -31,6 +31,14 @@ CONF_POWER_PIN = "power_pin"
|
||||||
CONF_INIT_AT = "init_at"
|
CONF_INIT_AT = "init_at"
|
||||||
CONF_ON_NOT_RESPONDING = "on_not_responding"
|
CONF_ON_NOT_RESPONDING = "on_not_responding"
|
||||||
|
|
||||||
|
MODEM_MODELS = ["BG96", "SIM800", "SIM7000", "SIM7600", "GENERIC"]
|
||||||
|
MODEM_MODELS_POWER = {
|
||||||
|
"BG96": {"ton": 600, "tonuart": 4900, "toff": 650, "toffuart": 2000},
|
||||||
|
"SIM800": {"ton": 1300, "tonuart": 3000, "toff": 200, "toffuart": 3000},
|
||||||
|
"SIM7000": {"ton": 1100, "tonuart": 4500, "toff": 1300, "toffuart": 1800},
|
||||||
|
"SIM7600": {"ton": 500, "tonuart": 12000, "toff": 2800, "toffuart": 25000},
|
||||||
|
}
|
||||||
|
|
||||||
modem_ns = cg.esphome_ns.namespace("modem")
|
modem_ns = cg.esphome_ns.namespace("modem")
|
||||||
ModemComponent = modem_ns.class_("ModemComponent", cg.Component)
|
ModemComponent = modem_ns.class_("ModemComponent", cg.Component)
|
||||||
ModemComponentState = modem_ns.enum("ModemComponentState")
|
ModemComponentState = modem_ns.enum("ModemComponentState")
|
||||||
|
@ -51,7 +59,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.GenerateID(): cv.declare_id(ModemComponent),
|
cv.GenerateID(): cv.declare_id(ModemComponent),
|
||||||
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_schema,
|
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_schema,
|
||||||
cv.Required(CONF_RX_PIN): pins.internal_gpio_output_pin_schema,
|
cv.Required(CONF_RX_PIN): pins.internal_gpio_output_pin_schema,
|
||||||
cv.Required(CONF_MODEL): cv.string,
|
cv.Required(CONF_MODEL): cv.one_of(*MODEM_MODELS, upper=True),
|
||||||
cv.Required(CONF_APN): cv.string,
|
cv.Required(CONF_APN): cv.string,
|
||||||
cv.Optional(CONF_STATUS_PIN): pins.internal_gpio_input_pin_schema,
|
cv.Optional(CONF_STATUS_PIN): pins.internal_gpio_input_pin_schema,
|
||||||
cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_schema,
|
cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_schema,
|
||||||
|
@ -87,6 +95,21 @@ CONFIG_SCHEMA = cv.All(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _final_validate(config):
|
||||||
|
if config.get(CONF_POWER_PIN, None) and not config.get(CONF_STATUS_PIN, None):
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"'{CONF_STATUS_PIN}' must be declared if using '{CONF_POWER_PIN}'"
|
||||||
|
)
|
||||||
|
if config.get(CONF_POWER_PIN, None):
|
||||||
|
if config[CONF_MODEL] not in MODEM_MODELS_POWER:
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"Modem model '{config[CONF_MODEL]}' has no power power specs."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(60.0)
|
@coroutine_with_priority(60.0)
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
add_idf_component(
|
add_idf_component(
|
||||||
|
@ -135,7 +158,15 @@ async def to_code(config):
|
||||||
for cmd in init_at:
|
for cmd in init_at:
|
||||||
cg.add(var.add_init_at_command(cmd))
|
cg.add(var.add_init_at_command(cmd))
|
||||||
|
|
||||||
cg.add(var.set_model(config[CONF_MODEL]))
|
modem_model = config[CONF_MODEL]
|
||||||
|
cg.add_define("USE_MODEM_MODEL", modem_model)
|
||||||
|
cg.add_define(f"USE_MODEM_MODEL_{modem_model}")
|
||||||
|
|
||||||
|
if power_spec := MODEM_MODELS_POWER.get(modem_model, None):
|
||||||
|
cg.add_define("USE_MODEM_POWER")
|
||||||
|
for spec, value in power_spec.items():
|
||||||
|
cg.add_define(f"USE_MODEM_POWER_{spec.upper()}", value)
|
||||||
|
|
||||||
cg.add(var.set_apn(config[CONF_APN]))
|
cg.add(var.set_apn(config[CONF_APN]))
|
||||||
|
|
||||||
tx_pin = await cg.gpio_pin_expression(config[CONF_TX_PIN])
|
tx_pin = await cg.gpio_pin_expression(config[CONF_TX_PIN])
|
||||||
|
@ -147,6 +178,7 @@ async def to_code(config):
|
||||||
if status_pin := config.get(CONF_STATUS_PIN, None):
|
if status_pin := config.get(CONF_STATUS_PIN, None):
|
||||||
pin = await cg.gpio_pin_expression(status_pin)
|
pin = await cg.gpio_pin_expression(status_pin)
|
||||||
cg.add(var.set_status_pin(pin))
|
cg.add(var.set_status_pin(pin))
|
||||||
|
cg.add_define("USE_MODEM_STATUS")
|
||||||
|
|
||||||
if power_pin := config.get(CONF_POWER_PIN, None):
|
if power_pin := config.get(CONF_POWER_PIN, None):
|
||||||
pin = await cg.gpio_pin_expression(power_pin)
|
pin = await cg.gpio_pin_expression(power_pin)
|
||||||
|
|
|
@ -50,7 +50,22 @@ ModemComponent::ModemComponent() {
|
||||||
global_modem_component = this;
|
global_modem_component = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModemComponent::dump_config() { ESP_LOGCONFIG(TAG, "Config Modem:"); }
|
void ModemComponent::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Config Modem:");
|
||||||
|
ESP_LOGCONFIG(TAG, " Model : %s", USE_MODEM_MODEL);
|
||||||
|
ESP_LOGCONFIG(TAG, " APN : %s", this->apn_.c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " PIN code : %s", (this->pin_code_.empty()) ? "No" : "Yes (not shown)");
|
||||||
|
ESP_LOGCONFIG(TAG, " Tx Pin : GPIO%u", this->tx_pin_->get_pin());
|
||||||
|
ESP_LOGCONFIG(TAG, " Rx Pin : GPIO%u", this->rx_pin_->get_pin());
|
||||||
|
ESP_LOGCONFIG(TAG, " Power pin : %s",
|
||||||
|
(this->power_pin_) ? ("GPIO" + std::to_string(this->power_pin_->get_pin())).c_str() : "Not defined");
|
||||||
|
if (this->status_pin_) {
|
||||||
|
std::string current_status = this->get_power_status() ? "ON" : "OFF";
|
||||||
|
ESP_LOGCONFIG(TAG, " Status pin: GPIO%u (current state %s)", this->status_pin_->get_pin(), current_status.c_str());
|
||||||
|
} else {
|
||||||
|
ESP_LOGCONFIG(TAG, " Status pin: Not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float ModemComponent::get_setup_priority() const { return setup_priority::WIFI; }
|
float ModemComponent::get_setup_priority() const { return setup_priority::WIFI; }
|
||||||
|
|
||||||
|
@ -153,33 +168,21 @@ void ModemComponent::reset_() {
|
||||||
|
|
||||||
this->dte_ = create_uart_dte(&this->dte_config_);
|
this->dte_ = create_uart_dte(&this->dte_config_);
|
||||||
|
|
||||||
assert(this->dte_);
|
|
||||||
|
|
||||||
ESP_LOGV(TAG, "DCE setup");
|
ESP_LOGV(TAG, "DCE setup");
|
||||||
|
|
||||||
// NOLINTBEGIN(bugprone-branch-clone)
|
#if defined(USE_MODEM_MODEL_GENERIC)
|
||||||
// ( because create_modem_dce(dce_factory::ModemType, config, std::move(dte), netif) is private )
|
this->dce = create_generic_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
||||||
switch (this->model_) {
|
#elif defined(USE_MODEM_MODEL_BG96)
|
||||||
case ModemModel::BG96:
|
this->dce = create_BG96_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
||||||
this->dce = create_BG96_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
#elif defined(USE_MODEM_MODEL_SIM800)
|
||||||
break;
|
this->dce = create_SIM800_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
||||||
case ModemModel::SIM800:
|
#elif defined(USE_MODEM_MODEL_SIM7000)
|
||||||
this->dce = create_SIM800_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
this->dce = create_SIM7000_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
||||||
break;
|
#elif defined(USE_MODEM_MODEL_SIM7600)
|
||||||
case ModemModel::SIM7000:
|
this->dce = create_SIM7600_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
||||||
this->dce = create_SIM7000_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
#else
|
||||||
break;
|
#error Modem model not known
|
||||||
case ModemModel::SIM7600:
|
#endif
|
||||||
this->dce = create_SIM7600_dce(&this->dce_config_, this->dte_, this->ppp_netif_);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGE(TAG, "Unknown modem model");
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// NOLINTEND(bugprone-branch-clone)
|
|
||||||
|
|
||||||
assert(this->dce);
|
|
||||||
|
|
||||||
// flow control not fully implemented, but kept here for future work
|
// flow control not fully implemented, but kept here for future work
|
||||||
if (this->dte_config_.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
if (this->dte_config_.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||||
|
@ -346,6 +349,7 @@ void ModemComponent::loop() {
|
||||||
this->state_ = ModemComponentState::DISCONNECTED;
|
this->state_ = ModemComponentState::DISCONNECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ModemComponentState::CONNECTED:
|
case ModemComponentState::CONNECTED:
|
||||||
if (!this->start_) {
|
if (!this->start_) {
|
||||||
this->state_ = ModemComponentState::DISCONNECTED;
|
this->state_ = ModemComponentState::DISCONNECTED;
|
||||||
|
@ -363,7 +367,7 @@ void ModemComponent::loop() {
|
||||||
if (!this->modem_ready()) {
|
if (!this->modem_ready()) {
|
||||||
ESP_LOGE(TAG, "modem not ready after hang up");
|
ESP_LOGE(TAG, "modem not ready after hang up");
|
||||||
}
|
}
|
||||||
this->set_timeout("wait_lost_ip", 60000, [this]() {
|
this->set_timeout("wait_lost_ip", 15000, [this]() {
|
||||||
// often reached on 7600, but not reached on 7670
|
// often reached on 7600, but not reached on 7670
|
||||||
ESP_LOGW(TAG, "No lost ip event received. Forcing disconnect state");
|
ESP_LOGW(TAG, "No lost ip event received. Forcing disconnect state");
|
||||||
|
|
||||||
|
@ -442,10 +446,7 @@ void ModemComponent::exit_cmux_() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModemComponent::get_power_status() {
|
bool ModemComponent::get_power_status() {
|
||||||
if (!this->status_pin_) {
|
#ifdef USE_MODEM_STATUS
|
||||||
ESP_LOGV(TAG, "No status pin, assuming the modem is ON");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool init_status = this->status_pin_->digital_read();
|
bool init_status = this->status_pin_->digital_read();
|
||||||
// The status pin might be floating when supposed to be low, at least on lilygo tsim7600
|
// The status pin might be floating when supposed to be low, at least on lilygo tsim7600
|
||||||
// as GPIO34 doesn't support pullup, we have to debounce it manually
|
// as GPIO34 doesn't support pullup, we have to debounce it manually
|
||||||
|
@ -458,21 +459,25 @@ bool ModemComponent::get_power_status() {
|
||||||
// ESP_LOGV(TAG, "Floating status pin detected for state %d", final_status);
|
// ESP_LOGV(TAG, "Floating status pin detected for state %d", final_status);
|
||||||
}
|
}
|
||||||
return final_status;
|
return final_status;
|
||||||
|
#else
|
||||||
|
// No status pin, assuming the modem is ON
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModemComponent::poweron_() {
|
void ModemComponent::poweron_() {
|
||||||
|
#ifdef USE_MODEM_POWER
|
||||||
if (this->power_pin_) {
|
if (this->power_pin_) {
|
||||||
Watchdog wdt(60);
|
Watchdog wdt(60);
|
||||||
ESP_LOGV(TAG, "Powering up modem with power_pin...");
|
ESP_LOGV(TAG, "Powering up modem with power_pin...");
|
||||||
this->power_transition_ = true;
|
this->power_transition_ = true;
|
||||||
this->power_pin_->digital_write(false);
|
this->power_pin_->digital_write(false);
|
||||||
// min 100 for SIM7600, but min 1200 for SIM800. min BG96: 650
|
// min 100 for SIM7600, but min 1200 for SIM800. min BG96: 650
|
||||||
delay(this->modem_model_ton_[this->model_]); // NOLINT
|
delay(USE_MODEM_POWER_TON);
|
||||||
this->power_pin_->digital_write(true);
|
this->power_pin_->digital_write(true);
|
||||||
// use a timout for long wait delay
|
// use a timout for long wait delay
|
||||||
uint32_t tonuart = this->modem_model_tonuart_[this->model_];
|
ESP_LOGD(TAG, "Will check that the modem is on in %.1fs...", float(USE_MODEM_POWER_TONUART) / 1000);
|
||||||
ESP_LOGD(TAG, "Will check that the modem is on in %.1fs...", float(tonuart) / 1000);
|
this->set_timeout("wait_poweron", USE_MODEM_POWER_TONUART, [this]() {
|
||||||
this->set_timeout("wait_poweron", tonuart, [this]() {
|
|
||||||
Watchdog wdt(60);
|
Watchdog wdt(60);
|
||||||
while (!this->get_power_status()) {
|
while (!this->get_power_status()) {
|
||||||
delay(this->command_delay_);
|
delay(this->command_delay_);
|
||||||
|
@ -487,9 +492,11 @@ void ModemComponent::poweron_() {
|
||||||
this->power_transition_ = false;
|
this->power_transition_ = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endif // USE_MODEM_POWER
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModemComponent::poweroff_() {
|
void ModemComponent::poweroff_() {
|
||||||
|
#ifdef USE_MODEM_POWER
|
||||||
if (this->get_power_status()) {
|
if (this->get_power_status()) {
|
||||||
if (this->power_pin_) {
|
if (this->power_pin_) {
|
||||||
ESP_LOGV(TAG, "Powering off modem with power pin...");
|
ESP_LOGV(TAG, "Powering off modem with power pin...");
|
||||||
|
@ -498,12 +505,11 @@ void ModemComponent::poweroff_() {
|
||||||
this->power_pin_->digital_write(true);
|
this->power_pin_->digital_write(true);
|
||||||
delay(10);
|
delay(10);
|
||||||
this->power_pin_->digital_write(false);
|
this->power_pin_->digital_write(false);
|
||||||
delay(this->modem_model_toff_[this->model_]);
|
delay(USE_MODEM_POWER_TOFF);
|
||||||
this->power_pin_->digital_write(true);
|
this->power_pin_->digital_write(true);
|
||||||
|
|
||||||
uint32_t toffuart = this->modem_model_toffuart_[this->model_];
|
ESP_LOGD(TAG, "Will check that the modem is off in %.1fs...", float(USE_MODEM_POWER_TOFFUART) / 1000);
|
||||||
ESP_LOGD(TAG, "Will check that the modem is off in %.1fs...", float(toffuart) / 1000);
|
this->set_timeout("wait_poweron", USE_MODEM_POWER_TOFFUART, [this]() {
|
||||||
this->set_timeout("wait_poweron", toffuart, [this]() {
|
|
||||||
Watchdog wdt(60);
|
Watchdog wdt(60);
|
||||||
|
|
||||||
while (this->get_power_status()) {
|
while (this->get_power_status()) {
|
||||||
|
@ -513,10 +519,8 @@ void ModemComponent::poweroff_() {
|
||||||
this->power_transition_ = false;
|
this->power_transition_ = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "Modem poweroff with AT command");
|
|
||||||
this->dce->power_down();
|
|
||||||
}
|
}
|
||||||
|
#endif // USE_MODEM_POWER
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModemComponent::dump_connect_params_() {
|
void ModemComponent::dump_connect_params_() {
|
||||||
|
|
|
@ -40,8 +40,6 @@ enum class ModemComponentState {
|
||||||
DISABLED,
|
DISABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ModemModel { BG96, SIM800, SIM7000, SIM7070, SIM7600, UNKNOWN };
|
|
||||||
|
|
||||||
class ModemComponent : public Component {
|
class ModemComponent : public Component {
|
||||||
public:
|
public:
|
||||||
ModemComponent();
|
ModemComponent();
|
||||||
|
@ -62,9 +60,6 @@ class ModemComponent : public Component {
|
||||||
void set_password(const std::string &password) { this->password_ = password; }
|
void set_password(const std::string &password) { this->password_ = password; }
|
||||||
void set_pin_code(const std::string &pin_code) { this->pin_code_ = pin_code; }
|
void set_pin_code(const std::string &pin_code) { this->pin_code_ = pin_code; }
|
||||||
void set_apn(const std::string &apn) { this->apn_ = apn; }
|
void set_apn(const std::string &apn) { this->apn_ = apn; }
|
||||||
void set_model(const std::string &model) {
|
|
||||||
this->model_ = this->modem_model_map_.count(model) ? modem_model_map_[model] : ModemModel::UNKNOWN;
|
|
||||||
}
|
|
||||||
void set_not_responding_cb(Trigger<> *not_responding_cb) { this->not_responding_cb_ = not_responding_cb; }
|
void set_not_responding_cb(Trigger<> *not_responding_cb) { this->not_responding_cb_ = not_responding_cb; }
|
||||||
void add_init_at_command(const std::string &cmd) { this->init_at_commands_.push_back(cmd); }
|
void add_init_at_command(const std::string &cmd) { this->init_at_commands_.push_back(cmd); }
|
||||||
std::string send_at(const std::string &cmd);
|
std::string send_at(const std::string &cmd);
|
||||||
|
@ -95,12 +90,6 @@ class ModemComponent : public Component {
|
||||||
std::string password_;
|
std::string password_;
|
||||||
std::string apn_;
|
std::string apn_;
|
||||||
std::vector<std::string> init_at_commands_;
|
std::vector<std::string> init_at_commands_;
|
||||||
ModemModel model_;
|
|
||||||
std::unordered_map<std::string, ModemModel> modem_model_map_ = {{"BG96", ModemModel::BG96},
|
|
||||||
{"SIM800", ModemModel::SIM800},
|
|
||||||
{"SIM7000", ModemModel::SIM7000},
|
|
||||||
{"SIM7070", ModemModel::SIM7070},
|
|
||||||
{"SIM7600", ModemModel::SIM7600}};
|
|
||||||
std::shared_ptr<DTE> dte_{nullptr};
|
std::shared_ptr<DTE> dte_{nullptr};
|
||||||
esp_netif_t *ppp_netif_{nullptr};
|
esp_netif_t *ppp_netif_{nullptr};
|
||||||
esp_modem_dte_config_t dte_config_;
|
esp_modem_dte_config_t dte_config_;
|
||||||
|
@ -117,31 +106,6 @@ class ModemComponent : public Component {
|
||||||
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;
|
||||||
// time needed for power_pin to be low for poweron
|
|
||||||
std::unordered_map<ModemModel, uint32_t> modem_model_ton_ = {{ModemModel::BG96, 600},
|
|
||||||
{ModemModel::SIM800, 1300},
|
|
||||||
{ModemModel::SIM7000, 1100},
|
|
||||||
{ModemModel::SIM7070, 1100},
|
|
||||||
{ModemModel::SIM7600, 500}};
|
|
||||||
// time to wait after poweron for uart to be ready
|
|
||||||
std::unordered_map<ModemModel, uint32_t> modem_model_tonuart_ = {{ModemModel::BG96, 4900},
|
|
||||||
{ModemModel::SIM800, 3000},
|
|
||||||
{ModemModel::SIM7000, 4500},
|
|
||||||
{ModemModel::SIM7070, 2500},
|
|
||||||
{ModemModel::SIM7600, 12000}};
|
|
||||||
// time needed for power_pin to be high for poweroff
|
|
||||||
std::unordered_map<ModemModel, uint32_t> modem_model_toff_ = {{ModemModel::BG96, 650},
|
|
||||||
{ModemModel::SIM800, 200},
|
|
||||||
{ModemModel::SIM7000, 1300},
|
|
||||||
{ModemModel::SIM7070, 1300},
|
|
||||||
{ModemModel::SIM7600, 2800}};
|
|
||||||
// time to wait after for poweroff for uart to be really closed
|
|
||||||
std::unordered_map<ModemModel, uint32_t> modem_model_toffuart_ = {{ModemModel::BG96, 2000},
|
|
||||||
{ModemModel::SIM800, 3000},
|
|
||||||
{ModemModel::SIM7000, 1800},
|
|
||||||
{ModemModel::SIM7070, 1800},
|
|
||||||
{ModemModel::SIM7600, 25000}};
|
|
||||||
|
|
||||||
// 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