mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 01:34:18 +01:00
gsm component
This commit is contained in:
parent
af3fb615ea
commit
0a01d1ef32
5 changed files with 597 additions and 1 deletions
113
esphome/components/gsm/__init__.py
Normal file
113
esphome/components/gsm/__init__.py
Normal file
|
@ -0,0 +1,113 @@
|
|||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_USE_ADDRESS,
|
||||
CONF_TX_PIN,
|
||||
CONF_RX_PIN,
|
||||
CONF_USERNAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_MODEL,
|
||||
)
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.core import coroutine_with_priority
|
||||
from esphome.components.esp32 import add_idf_component, add_idf_sdkconfig_option
|
||||
|
||||
CODEOWNERS = ["@oarcher"]
|
||||
DEPENDENCIES = ["esp32"]
|
||||
AUTO_LOAD = ["network"]
|
||||
|
||||
CONF_POWER_PIN = "power_pin"
|
||||
CONF_FLIGHT_PIN = "flight_pin"
|
||||
CONF_PIN_CODE = "pin_code"
|
||||
CONF_APN = "apn"
|
||||
CONF_STATUS_PIN = "status_pin"
|
||||
CONF_DTR_PIN = "dtr_pin"
|
||||
|
||||
|
||||
gsm_ns = cg.esphome_ns.namespace("gsm")
|
||||
GSMComponent = gsm_ns.class_("GSMComponent", cg.Component)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(GSMComponent),
|
||||
cv.Required(CONF_TX_PIN): cv.positive_int,
|
||||
cv.Required(CONF_RX_PIN): cv.positive_int,
|
||||
cv.Required(CONF_MODEL): cv.string,
|
||||
cv.Required(CONF_APN): cv.string,
|
||||
cv.Optional(CONF_FLIGHT_PIN): cv.positive_int,
|
||||
cv.Optional(CONF_POWER_PIN): cv.positive_int,
|
||||
cv.Optional(CONF_STATUS_PIN): cv.positive_int,
|
||||
cv.Optional(CONF_DTR_PIN): cv.positive_int,
|
||||
cv.Optional(CONF_PIN_CODE): cv.string_strict,
|
||||
cv.Optional(CONF_USERNAME): cv.string,
|
||||
cv.Optional(CONF_PASSWORD): cv.string,
|
||||
cv.Optional(CONF_USE_ADDRESS): cv.string,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.require_framework_version(
|
||||
esp_idf=cv.Version(4, 0, 0), # 5.2.0 OK
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@coroutine_with_priority(60.0)
|
||||
async def to_code(config):
|
||||
add_idf_component(
|
||||
name="esp_modem",
|
||||
repo="https://github.com/espressif/esp-protocols.git",
|
||||
ref="modem-v1.1.0",
|
||||
path="components/esp_modem",
|
||||
)
|
||||
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_TIMEOUT_S", 60)
|
||||
add_idf_sdkconfig_option("CONFIG_PPP", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_PPP_SUPPORT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_PPP_PAP_SUPPORT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_PPP_PAP_SUPPORT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LOG_DEFAULT_LEVEL_VERBOSE", True)
|
||||
# add_idf_sdkconfig_option("CONFIG_LOG_DEFAULT_LEVEL_DEBUG", True)
|
||||
add_idf_sdkconfig_option("CONFIG_EXAMPLE_CLOSE_CMUX_AT_END", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_MODEM_CMUX_DELAY_AFTER_DLCI_SETUP", 0)
|
||||
add_idf_sdkconfig_option("CONFIG_PPP_SUPPORT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_PPP_NOTIFY_PHASE_SUPPORT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_PPP_CHAP_SUPPORT", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION", True)
|
||||
add_idf_sdkconfig_option("CONFIG_EXAMPLE_MODEM_PPP_APN", "orange")
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_PPP_NOTIFY_PHASE_SUPPORT", True)
|
||||
|
||||
cg.add_define("USE_GSM")
|
||||
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
if use_address := config.get(CONF_USE_ADDRESS, None):
|
||||
cg.add(var.set_use_address(use_address))
|
||||
|
||||
if username := config.get(CONF_USERNAME, None):
|
||||
cg.add(var.set_username(username))
|
||||
|
||||
if password := config.get(CONF_PASSWORD, None):
|
||||
cg.add(var.set_password(password))
|
||||
|
||||
if pin_code := config.get(CONF_PIN_CODE, None):
|
||||
cg.add(var.set_pin_code(pin_code))
|
||||
|
||||
cg.add(var.set_model(config[CONF_MODEL]))
|
||||
cg.add(var.set_apn(config[CONF_APN]))
|
||||
|
||||
gpio_num_t = cg.global_ns.enum("gpio_num_t")
|
||||
|
||||
cg.add(var.set_rx_pin(getattr(gpio_num_t, f"GPIO_NUM_{config[CONF_RX_PIN]}")))
|
||||
cg.add(var.set_tx_pin(getattr(gpio_num_t, f"GPIO_NUM_{config[CONF_TX_PIN]}")))
|
||||
if pwr_pin := config.get(CONF_POWER_PIN, None):
|
||||
cg.add(var.set_power_pin(getattr(gpio_num_t, f"GPIO_NUM_{pwr_pin}")))
|
||||
if flight_pin := config.get(CONF_FLIGHT_PIN, None):
|
||||
cg.add(var.set_flight_pin(getattr(gpio_num_t, f"GPIO_NUM_{flight_pin}")))
|
||||
if pin_status := config.get(CONF_STATUS_PIN, None):
|
||||
cg.add(var.set_status_pin(getattr(gpio_num_t, f"GPIO_NUM_{pin_status}")))
|
||||
if pin_dtr := config.get(CONF_DTR_PIN, None):
|
||||
cg.add(var.set_dtr_pin(getattr(gpio_num_t, f"GPIO_NUM_{pin_dtr}")))
|
||||
|
||||
await cg.register_component(var, config)
|
369
esphome/components/gsm/gsm_component.cpp
Normal file
369
esphome/components/gsm/gsm_component.cpp
Normal file
|
@ -0,0 +1,369 @@
|
|||
#if defined(USE_ESP32) || defined(USE_ESP_IDF)
|
||||
#include "gsm_component.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
#include <esp_netif.h>
|
||||
#include <esp_netif_ppp.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_event.h>
|
||||
#include <cxx_include/esp_modem_dte.hpp>
|
||||
#include <esp_modem_config.h>
|
||||
#include <cxx_include/esp_modem_api.hpp>
|
||||
#include <driver/gpio.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define CONFIG_MODEM_UART_RX_BUFFER_SIZE 1024
|
||||
#define CONFIG_MODEM_UART_TX_BUFFER_SIZE 512
|
||||
#define CONFIG_MODEM_UART_EVENT_QUEUE_SIZE 30
|
||||
#define CONFIG_MODEM_UART_EVENT_TASK_STACK_SIZE 2048
|
||||
#define CONFIG_MODEM_UART_EVENT_TASK_PRIORITY 5
|
||||
|
||||
namespace esphome {
|
||||
namespace gsm {
|
||||
|
||||
GSMComponent *global_gsm_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
#define ESPHL_ERROR_CHECK(err, message) \
|
||||
if ((err) != ESP_OK) { \
|
||||
ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \
|
||||
this->mark_failed(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
using namespace esp_modem;
|
||||
|
||||
GSMComponent::GSMComponent() { global_gsm_component = this; }
|
||||
|
||||
void GSMComponent::dump_config() { ESP_LOGCONFIG(TAG, "Config GSM:"); }
|
||||
|
||||
float GSMComponent::get_setup_priority() const { return setup_priority::WIFI; }
|
||||
|
||||
bool GSMComponent::can_proceed() { return this->is_connected(); }
|
||||
|
||||
network::IPAddresses GSMComponent::get_ip_addresses() {
|
||||
network::IPAddresses addresses;
|
||||
esp_netif_ip_info_t ip;
|
||||
ESP_LOGV(TAG, "get_ip_addresses");
|
||||
esp_err_t err = esp_netif_get_ip_info(this->ppp_netif, &ip);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err));
|
||||
// TODO: do something smarter
|
||||
// return false;
|
||||
} else {
|
||||
addresses[0] = network::IPAddress(&ip.ip);
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
std::string GSMComponent::get_use_address() const {
|
||||
if (this->use_address_.empty()) {
|
||||
return App.get_name() + ".local";
|
||||
}
|
||||
return this->use_address_;
|
||||
}
|
||||
|
||||
void GSMComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
|
||||
|
||||
bool GSMComponent::is_connected() { return this->state_ == GSMComponentState::CONNECTED; }
|
||||
|
||||
void GSMComponent::setup() {
|
||||
ESP_LOGI(TAG, "Setting up GSM...");
|
||||
|
||||
this->config_gpio_();
|
||||
|
||||
ESP_LOGI(TAG, "Status: %d", (int) this->get_status());
|
||||
|
||||
// to be sure the modem is not allready connected
|
||||
// this->powerdown();
|
||||
|
||||
ESP_LOGV(TAG, "DTE setup");
|
||||
esp_modem_dte_config_t dte_config_ = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
this->dte_config = dte_config_;
|
||||
|
||||
// this->dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
this->dte_config.uart_config.tx_io_num = this->tx_pin_;
|
||||
this->dte_config.uart_config.rx_io_num = this->rx_pin_;
|
||||
// this->dte_config.uart_config.rts_io_num = static_cast<gpio_num_t>( CONFIG_EXAMPLE_MODEM_UART_RTS_PIN);
|
||||
// this->dte_config.uart_config.cts_io_num = static_cast<gpio_num_t>( CONFIG_EXAMPLE_MODEM_UART_CTS_PIN);
|
||||
this->dte_config.uart_config.rx_buffer_size = CONFIG_MODEM_UART_RX_BUFFER_SIZE;
|
||||
this->dte_config.uart_config.tx_buffer_size = CONFIG_MODEM_UART_TX_BUFFER_SIZE;
|
||||
this->dte_config.uart_config.event_queue_size = CONFIG_MODEM_UART_EVENT_QUEUE_SIZE;
|
||||
this->dte_config.task_stack_size = CONFIG_MODEM_UART_EVENT_TASK_STACK_SIZE * 2;
|
||||
this->dte_config.task_priority = CONFIG_MODEM_UART_EVENT_TASK_PRIORITY;
|
||||
this->dte_config.dte_buffer_size = CONFIG_MODEM_UART_RX_BUFFER_SIZE / 2;
|
||||
|
||||
this->dte = esp_modem::create_uart_dte(&this->dte_config);
|
||||
|
||||
assert(this->dte);
|
||||
|
||||
ESP_LOGV(TAG, "Set APN: %s", this->apn_.c_str());
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(this->apn_.c_str());
|
||||
|
||||
ESP_LOGV(TAG, "PPP netif setup");
|
||||
esp_err_t err;
|
||||
err = esp_netif_init();
|
||||
ESPHL_ERROR_CHECK(err, "PPP netif init error");
|
||||
err = esp_event_loop_create_default();
|
||||
ESPHL_ERROR_CHECK(err, "PPP event loop init error");
|
||||
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
|
||||
|
||||
this->ppp_netif = esp_netif_new(&netif_ppp_config);
|
||||
assert(this->ppp_netif);
|
||||
if (!this->username_.empty()) {
|
||||
ESP_LOGV(TAG, "Set auth: username: %s password: %s", this->username_.c_str(), this->password_.c_str());
|
||||
ESPHL_ERROR_CHECK(esp_netif_ppp_set_auth(this->ppp_netif, NETIF_PPP_AUTHTYPE_PAP, this->username_.c_str(),
|
||||
this->password_.c_str()),
|
||||
"ppp set auth");
|
||||
}
|
||||
// dns setup not needed (perhaps fallback ?)
|
||||
// esp_netif_dns_info_t dns_main = {};
|
||||
// dns_main.ip.u_addr.ip4.addr = esp_ip4addr_aton("8.8.8.8");
|
||||
// dns_main.ip.type = ESP_IPADDR_TYPE_V4;
|
||||
// ESPHL_ERROR_CHECK(esp_netif_set_dns_info(this->ppp_netif, ESP_NETIF_DNS_MAIN, &dns_main), "dns_main");
|
||||
|
||||
// Register user defined event handers
|
||||
err = esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, &GSMComponent::got_ip_event_handler, nullptr);
|
||||
ESPHL_ERROR_CHECK(err, "GOT IP event handler register error");
|
||||
|
||||
ESP_LOGV(TAG, "DCE setup");
|
||||
|
||||
switch (this->model_) {
|
||||
case GSMModel::BG96:
|
||||
this->dce = create_BG96_dce(&dce_config, dte, this->ppp_netif);
|
||||
break;
|
||||
case GSMModel::SIM800:
|
||||
this->dce = create_SIM800_dce(&dce_config, dte, this->ppp_netif);
|
||||
break;
|
||||
case GSMModel::SIM7000:
|
||||
this->dce = create_SIM7000_dce(&dce_config, dte, this->ppp_netif);
|
||||
break;
|
||||
case GSMModel::SIM7600:
|
||||
this->dce = create_SIM7600_dce(&dce_config, dte, this->ppp_netif);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown model");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(this->dce);
|
||||
|
||||
this->started_ = true;
|
||||
ESP_LOGV(TAG, "Setup finished");
|
||||
}
|
||||
|
||||
void GSMComponent::start_connect_() {
|
||||
this->connect_begin_ = millis();
|
||||
this->status_set_warning();
|
||||
|
||||
ESP_LOGI(TAG, "Status: %d", (int) this->get_status());
|
||||
|
||||
this->poweron();
|
||||
|
||||
ESP_LOGI(TAG, "Status: %d", (int) this->get_status());
|
||||
|
||||
// esp_err_t err;
|
||||
// err = esp_netif_set_hostname(this->ppp_netif, App.get_name().c_str());
|
||||
// if (err != ERR_OK) {
|
||||
// ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
|
||||
// }
|
||||
|
||||
global_gsm_component->got_ipv4_address_ = false; // why not this ?
|
||||
|
||||
this->dce->set_mode(esp_modem::modem_mode::CMUX_MANUAL_COMMAND);
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
command_result res = command_result::TIMEOUT;
|
||||
|
||||
int retry = 0;
|
||||
while (res != command_result::OK) {
|
||||
res = this->dce->sync();
|
||||
if (res != command_result::OK) {
|
||||
ESP_LOGW(TAG, "modem not responding");
|
||||
ESP_LOGI(TAG, "Status: %d", (int) this->get_status());
|
||||
this->dce->set_command_mode();
|
||||
App.feed_wdt();
|
||||
vTaskDelay(pdMS_TO_TICKS(7000));
|
||||
}
|
||||
retry++;
|
||||
if (retry > 10)
|
||||
break;
|
||||
}
|
||||
|
||||
if (res != command_result::OK) {
|
||||
ESP_LOGW(TAG, "Unable to sync modem. Will retry later");
|
||||
this->powerdown();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
if (command_result::OK != dce->set_flow_control(2, 2)) {
|
||||
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "set_flow_control OK");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "not set_flow_control, because 2-wire mode active.");
|
||||
}
|
||||
|
||||
/* Setup basic operation mode for the DCE (pin if used, CMUX mode) */
|
||||
if (!this->pin_code_.empty()) {
|
||||
bool pin_ok = true;
|
||||
ESP_LOGV(TAG, "Set pin code: %s", this->pin_code_.c_str());
|
||||
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
|
||||
ESP_MODEM_THROW_IF_FALSE(dce->set_pin(this->pin_code_) == command_result::OK, "Cannot set PIN!");
|
||||
vTaskDelay(pdMS_TO_TICKS(2000)); // Need to wait for some time after unlocking the SIM
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Entering CMUX mode");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
|
||||
if (this->dce->set_mode(esp_modem::modem_mode::CMUX_MODE)) {
|
||||
ESP_LOGD(TAG, "Modem has correctly entered multiplexed command/data mode");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to configure multiplexed command mode... exiting");
|
||||
return;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
}
|
||||
|
||||
void GSMComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
ESP_LOGW(TAG, "[IP event] Got IP " IPSTR, IP2STR(&ip_info->ip));
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // FIXME tmp
|
||||
global_gsm_component->got_ipv4_address_ = true;
|
||||
global_gsm_component->connected_ = true;
|
||||
}
|
||||
|
||||
void GSMComponent::loop() {
|
||||
const uint32_t now = millis();
|
||||
|
||||
switch (this->state_) {
|
||||
case GSMComponentState::STOPPED:
|
||||
if (this->started_) {
|
||||
ESP_LOGI(TAG, "Starting gsm connection");
|
||||
this->state_ = GSMComponentState::CONNECTING;
|
||||
this->start_connect_();
|
||||
}
|
||||
break;
|
||||
case GSMComponentState::CONNECTING:
|
||||
if (!this->started_) {
|
||||
ESP_LOGI(TAG, "Stopped ethernet connection");
|
||||
this->state_ = GSMComponentState::STOPPED;
|
||||
} else if (this->connected_) {
|
||||
// connection established
|
||||
ESP_LOGI(TAG, "Connected via GSM");
|
||||
this->state_ = GSMComponentState::CONNECTED;
|
||||
|
||||
this->dump_connect_params_();
|
||||
this->status_clear_warning();
|
||||
} else if (now - this->connect_begin_ > 45000) {
|
||||
ESP_LOGW(TAG, "Connecting via GSM failed! Re-connecting...");
|
||||
this->start_connect_();
|
||||
}
|
||||
break;
|
||||
case GSMComponentState::CONNECTED:
|
||||
if (!this->started_) {
|
||||
ESP_LOGI(TAG, "Stopped GSM connection");
|
||||
this->state_ = GSMComponentState::STOPPED;
|
||||
} else if (!this->connected_) {
|
||||
ESP_LOGW(TAG, "Connection via GSM lost! Re-connecting...");
|
||||
this->state_ = GSMComponentState::CONNECTING;
|
||||
this->start_connect_();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GSMComponent::dump_connect_params_() {
|
||||
esp_netif_ip_info_t ip;
|
||||
esp_netif_get_ip_info(this->ppp_netif, &ip);
|
||||
ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(&ip.ip).str().c_str());
|
||||
ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(&ip.netmask).str().c_str());
|
||||
ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(&ip.gw).str().c_str());
|
||||
|
||||
const ip_addr_t *dns_main_ip = dns_getserver(ESP_NETIF_DNS_MAIN);
|
||||
const ip_addr_t *dns_backup_ip = dns_getserver(ESP_NETIF_DNS_BACKUP);
|
||||
const ip_addr_t *dns_fallback_ip = dns_getserver(ESP_NETIF_DNS_FALLBACK);
|
||||
|
||||
ESP_LOGCONFIG(TAG, " DNS main: %s", network::IPAddress(dns_main_ip).str().c_str());
|
||||
ESP_LOGCONFIG(TAG, " DNS backup: %s", network::IPAddress(dns_backup_ip).str().c_str());
|
||||
ESP_LOGCONFIG(TAG, " DNS fallback: %s", network::IPAddress(dns_fallback_ip).str().c_str());
|
||||
}
|
||||
|
||||
void GSMComponent::config_gpio_() {
|
||||
ESP_LOGV(TAG, "Configuring GPIOs...");
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 0ULL;
|
||||
if (this->power_pin_ != gpio_num_t::GPIO_NUM_NC) {
|
||||
io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->power_pin_);
|
||||
}
|
||||
if (this->flight_pin_ != gpio_num_t::GPIO_NUM_NC) {
|
||||
io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->flight_pin_);
|
||||
}
|
||||
if (this->dtr_pin_ != gpio_num_t::GPIO_NUM_NC) {
|
||||
io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->dtr_pin_);
|
||||
}
|
||||
// io_conf.pin_bit_mask = ((1ULL << this->power_pin_) | (1ULL << this->flight_pin_));
|
||||
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
|
||||
gpio_config(&io_conf);
|
||||
|
||||
io_conf.pin_bit_mask = 0ULL;
|
||||
if (this->status_pin_ != gpio_num_t::GPIO_NUM_NC) {
|
||||
io_conf.pin_bit_mask = io_conf.pin_bit_mask | (1ULL << this->status_pin_);
|
||||
}
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
void GSMComponent::poweron(void) {
|
||||
/* Power on the modem */
|
||||
|
||||
ESP_LOGI(TAG, "Status: %d", (int) this->get_status());
|
||||
|
||||
ESP_LOGI(TAG, "Power on modem");
|
||||
// https://github.com/Xinyuan-LilyGO/LilyGO-T-SIM7000G/issues/251
|
||||
if (this->power_pin_ != gpio_num_t::GPIO_NUM_NC) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 0)); // low = on, high = off
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 1));
|
||||
vTaskDelay(pdMS_TO_TICKS(1010));
|
||||
ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 0));
|
||||
vTaskDelay(pdMS_TO_TICKS(4050)); // Ton uart 4.5sec but seems to need ~7sec after hard (button) reset
|
||||
} else {
|
||||
ESP_LOGW(TAG, "No power pin defined. Trying to continue");
|
||||
}
|
||||
|
||||
if (this->flight_pin_ != gpio_num_t::GPIO_NUM_NC) {
|
||||
ESP_ERROR_CHECK(gpio_set_level(this->flight_pin_, 1)); // need to be high
|
||||
} else {
|
||||
ESP_LOGW(TAG, "No flight pin defined. Trying to continue");
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(15000));
|
||||
App.feed_wdt();
|
||||
}
|
||||
|
||||
void GSMComponent::powerdown(void) {
|
||||
ESP_LOGI(TAG, "Power down modem");
|
||||
ESP_ERROR_CHECK(gpio_set_level(this->power_pin_, 1));
|
||||
}
|
||||
|
||||
} // namespace gsm
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
99
esphome/components/gsm/gsm_component.h
Normal file
99
esphome/components/gsm/gsm_component.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_ESP_IDF)
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <cxx_include/esp_modem_api.hpp>
|
||||
#include <esp_modem_config.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace esphome {
|
||||
namespace gsm {
|
||||
|
||||
static const char *const TAG = "gsm";
|
||||
|
||||
enum class GSMComponentState {
|
||||
STOPPED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
};
|
||||
|
||||
enum class GSMModel { BG96, SIM800, SIM7000, SIM7070, SIM7070_GNSS, SIM7600, UNKNOWN };
|
||||
|
||||
class GSMComponent : public Component {
|
||||
public:
|
||||
GSMComponent();
|
||||
void dump_config() override;
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
bool is_connected();
|
||||
float get_setup_priority() const override;
|
||||
bool can_proceed() override;
|
||||
void on_shutdown() override { powerdown(); }
|
||||
network::IPAddresses get_ip_addresses();
|
||||
std::string get_use_address() const;
|
||||
void set_use_address(const std::string &use_address);
|
||||
void poweron();
|
||||
void powerdown();
|
||||
void set_rx_pin(gpio_num_t rx_pin) { this->rx_pin_ = rx_pin; }
|
||||
void set_tx_pin(gpio_num_t tx_pin) { this->tx_pin_ = tx_pin; }
|
||||
void set_power_pin(gpio_num_t power_pin) { this->power_pin_ = power_pin; }
|
||||
void set_flight_pin(gpio_num_t flight_pin) { this->flight_pin_ = flight_pin; }
|
||||
void set_username(std::string username) { this->username_ = username; }
|
||||
void set_password(std::string password) { this->password_ = password; }
|
||||
void set_pin_code(std::string pin_code) { this->pin_code_ = pin_code; }
|
||||
void set_apn(std::string apn) { this->apn_ = apn; }
|
||||
void set_status_pin(gpio_num_t status_pin) { this->status_pin_ = status_pin; }
|
||||
void set_dtr_pin(gpio_num_t dtr_pin) { this->dtr_pin_ = dtr_pin; }
|
||||
void set_model(std::string model) {
|
||||
this->model_ = this->gsm_model_map_.count(model) ? gsm_model_map_[model] : GSMModel::UNKNOWN;
|
||||
}
|
||||
bool get_status() { return gpio_get_level(this->status_pin_); }
|
||||
|
||||
protected:
|
||||
gpio_num_t rx_pin_ = gpio_num_t::GPIO_NUM_NC;
|
||||
gpio_num_t tx_pin_ = gpio_num_t::GPIO_NUM_NC;
|
||||
gpio_num_t power_pin_ = gpio_num_t::GPIO_NUM_NC;
|
||||
gpio_num_t flight_pin_ = gpio_num_t::GPIO_NUM_NC;
|
||||
gpio_num_t status_pin_ = gpio_num_t::GPIO_NUM_NC;
|
||||
gpio_num_t dtr_pin_ = gpio_num_t::GPIO_NUM_NC;
|
||||
|
||||
std::string pin_code_;
|
||||
std::string username_;
|
||||
std::string password_;
|
||||
std::string apn_;
|
||||
GSMModel model_;
|
||||
std::unordered_map<std::string, GSMModel> gsm_model_map_ = {{"BG96", GSMModel::BG96},
|
||||
{"SIM800", GSMModel::SIM800},
|
||||
{"SIM7000", GSMModel::SIM7000},
|
||||
{"SIM7070", GSMModel::SIM7070},
|
||||
{"SIM7070_GNSS", GSMModel::SIM7070_GNSS},
|
||||
{"SIM7600", GSMModel::SIM7600}};
|
||||
std::shared_ptr<esp_modem::DTE> dte;
|
||||
std::unique_ptr<esp_modem::DCE> dce; // public ?
|
||||
esp_modem::esp_netif_t *ppp_netif{nullptr};
|
||||
esp_modem_dte_config_t dte_config;
|
||||
GSMComponentState state_{GSMComponentState::STOPPED};
|
||||
void start_connect_();
|
||||
bool started_{false};
|
||||
bool connected_{false};
|
||||
bool got_ipv4_address_{false};
|
||||
uint32_t connect_begin_;
|
||||
static void got_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_;
|
||||
void config_gpio_();
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern GSMComponent *global_gsm_component;
|
||||
|
||||
} // namespace gsm
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include <cstdio>
|
||||
#include <array>
|
||||
#include "esphome/core/macros.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#if defined(USE_ESP_IDF) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
|
||||
#include <lwip/ip_addr.h>
|
||||
|
@ -116,7 +117,7 @@ struct IPAddress {
|
|||
bool is_set() { return !ip_addr_isany(&ip_addr_); }
|
||||
bool is_ip4() { return IP_IS_V4(&ip_addr_); }
|
||||
bool is_ip6() { return IP_IS_V6(&ip_addr_); }
|
||||
std::string str() const { return ipaddr_ntoa(&ip_addr_); }
|
||||
std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); }
|
||||
bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
|
||||
bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
|
||||
IPAddress &operator+=(uint8_t increase) {
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include "esphome/components/ethernet/ethernet_component.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_GSM
|
||||
#include "esphome/components/gsm/gsm_component.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace network {
|
||||
|
||||
|
@ -23,6 +27,11 @@ bool is_connected() {
|
|||
return wifi::global_wifi_component->is_connected();
|
||||
#endif
|
||||
|
||||
#ifdef USE_GSM
|
||||
if (gsm::global_gsm_component != nullptr)
|
||||
return gsm::global_gsm_component->is_connected();
|
||||
#endif
|
||||
|
||||
#ifdef USE_HOST
|
||||
return true; // Assume its connected
|
||||
#endif
|
||||
|
@ -46,6 +55,7 @@ network::IPAddresses get_ip_addresses() {
|
|||
if (wifi::global_wifi_component != nullptr)
|
||||
return wifi::global_wifi_component->get_ip_addresses();
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -57,6 +67,10 @@ std::string get_use_address() {
|
|||
#ifdef USE_WIFI
|
||||
if (wifi::global_wifi_component != nullptr)
|
||||
return wifi::global_wifi_component->get_use_address();
|
||||
#endif
|
||||
#ifdef USE_GSM
|
||||
if (gsm::global_gsm_component != nullptr)
|
||||
return gsm::global_gsm_component->get_use_address();
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue