espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
12.98k stars 7.29k forks source link

Switch between network interfaces #9983

Closed MehdiSadeghii closed 1 day ago

MehdiSadeghii commented 4 days ago

Board

ESP32 Dev Module

Device Description

When using Ethernet and WiFi and PPP together, we can't switch between interfaces easily all interfaces, there's jut printTo method which we can print them. now my idea is to have a function which returns all NetworkInterface and when we want to set default interface we can choose interface from the list we extracted.

This feature is needed when we have more than one interfaces but our default interface doesn't have access to the internet. In this case we need to switch to another interface.

Hardware Configuration

gpio 16, 17 used for SIM800, VSPI is used for ETH

Version

latest master (checkout manually)

IDE Name

Arduino IDE

Operating System

Windows 10

Flash frequency

80 MHz

PSRAM enabled

yes

Upload speed

115200

Description

when my WiFi doesn't have access to the internet I need to switch to another interface.

Sketch

/*
    This sketch shows the Ethernet event usage

*/
#include <PPP.h>
#include <WiFi.h>
#include <ETH.h>
#include <SPI.h>

#include <Ticker.h>

#include <PubSubClient.h>

#define PPP_MODEM_APN "mtnirancell"
#define PPP_MODEM_PIN "0000" // or NULL

NetworkClient net;
PubSubClient mqtt("xxx", 1883, net);

Ticker GSMTimer;

#ifndef ETH_PHY_TYPE
#define ETH_PHY_TYPE ETH_PHY_W5500
#define ETH_PHY_ADDR 1
#define ETH_PHY_CS 5
#define ETH_PHY_IRQ 34
#define ETH_PHY_RST 33
#endif

// SPI pins
#define ETH_SPI_SCK 18
#define ETH_SPI_MISO 19
#define ETH_SPI_MOSI 23

#define PPP_MODEM_RST 13
#define PPP_MODEM_RST_DELAY 2500
#define PPP_MODEM_RST_LOW true // active LOW
#define PPP_MODEM_TX 17
#define PPP_MODEM_RX 16
#define PPP_MODEM_RTS -1
#define PPP_MODEM_CTS -1
#define PPP_MODEM_FC ESP_MODEM_FLOW_CONTROL_NONE
#define PPP_MODEM_MODEL PPP_MODEM_SIM800

bool eth_connected = false;
bool wifi_connected = false;
bool gsm_connected = false;

void onMqttMessage(char *topic, byte *payload, unsigned int length)
{
    Serial.println("--------------------------------------------------------------");
    Serial.println("Message Recieved!");
    Network.printTo(Serial);
}

void onEvent(arduino_event_id_t event, arduino_event_info_t info)
{
    switch (event)
    {
    case ARDUINO_EVENT_PPP_START:
        Serial.println("PPP Started");
        break;

    case ARDUINO_EVENT_PPP_CONNECTED:
        Serial.println("PPP Connected");

        break;

    case ARDUINO_EVENT_PPP_GOT_IP:
        Serial.println("PPP Got IP");
        gsm_connected = true;
        break;

    case ARDUINO_EVENT_PPP_LOST_IP:
        Serial.println("PPP Lost IP");
        gsm_connected = false;
        break;

    case ARDUINO_EVENT_PPP_DISCONNECTED:
        Serial.println("PPP Disconnected");
        gsm_connected = false;
        break;

    case ARDUINO_EVENT_PPP_STOP:
        Serial.println("PPP Stopped");
        gsm_connected = false;
        break;

    case ARDUINO_EVENT_WIFI_STA_GOT_IP:
        wifi_connected = true;
        Serial.println("WiFi Connected");
        break;

    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
        wifi_connected = false;
        Serial.println("WiFi Disconnected");
        break;

    case ARDUINO_EVENT_WIFI_STA_LOST_IP:
        wifi_connected = false;
        Serial.println("WiFi Disconnected");
        break;

    case ARDUINO_EVENT_ETH_START:
        Serial.println("ETH Started");
        // set eth hostname here
        ETH.setHostname("esp32-eth0");
        break;

    case ARDUINO_EVENT_ETH_CONNECTED:
        Serial.println("ETH Connected");
        break;

    case ARDUINO_EVENT_ETH_GOT_IP:
        Serial.printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif));
        Serial.println(ETH);
        eth_connected = true;

        break;

    case ARDUINO_EVENT_ETH_LOST_IP:
        Serial.println("ETH Lost IP");
        eth_connected = false;
        break;

    case ARDUINO_EVENT_ETH_DISCONNECTED:
        Serial.println("ETH Disconnected");
        eth_connected = false;
        break;

    case ARDUINO_EVENT_ETH_STOP:
        Serial.println("ETH Stopped");
        eth_connected = false;
        break;

    default:
        break;
    }
}

void connectGSM()
{
    bool attached = PPP.attached();
    if (attached)
    {
        GSMTimer.detach();

        Serial.println("Switching to data mode...");
        PPP.mode(ESP_MODEM_MODE_CMUX);  // Data and Command mixed mode
        if (!PPP.waitStatusBits(ESP_NETIF_CONNECTED_BIT, 1000)) 
        {
            Serial.println("Failed to connect to internet!");
        } 
        else 
        {
            Serial.println("Connected to internet!");
        }
    }
    else
    {
        Serial.println("Failed to connect to internet!");
    }

}

void configureGSM()
{
    // Configure the modem
    PPP.setApn(PPP_MODEM_APN);
    PPP.setPin(PPP_MODEM_PIN);
    PPP.setResetPin(PPP_MODEM_RST, PPP_MODEM_RST_LOW, PPP_MODEM_RST_DELAY);
    PPP.setPins(PPP_MODEM_TX, PPP_MODEM_RX, PPP_MODEM_RTS, PPP_MODEM_CTS, PPP_MODEM_FC);

    Serial.println("Starting the modem. It might take a while!");
    PPP.begin(PPP_MODEM_MODEL);

    Serial.print("Manufacturer: ");
    Serial.println(PPP.cmd("AT+CGMI", 10000));
    Serial.print("Model: ");
    Serial.println(PPP.moduleName());
    Serial.print("IMEI: ");
    Serial.println(PPP.IMEI());

    Serial.println("Connecting to GSM Network");

    GSMTimer.attach(1, connectGSM);
}

void setup()
{
    Serial.begin(115200);

    Network.onEvent(onEvent);
    mqtt.setCallback(onMqttMessage);

    SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI);
    ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI);

    WiFi.begin("BehamadModem", "P@ssword1234");

    configureGSM();
    WiFi.setAutoReconnect(true);

}
int counter = 0;
void loop()
{
    if (eth_connected || wifi_connected || gsm_connected)
    {
        if (!mqtt.connected())
        {
            if (mqtt.connect("esp32TestEthernet", "xxx", "xxx"))
            {
                Serial.println("mqtt connected");
                mqtt.subscribe("xxx");
            }
            else
            {
                Serial.printf("MQTT connection failed, rc= %d\r\n", mqtt.state());
                Serial.println("******************************************************");
                if (counter ++ > 5)
                {
                    Serial.println("Changing Interface....");
                    counter = 0;
                    Network.printTo(Serial);

                    NetworkInterface *irfc =  Network.getDefaultInterface();
                    Serial.println(irfc->printTo(Serial));
                    Network.

                }

            }
        }
        else
        {
            mqtt.loop();
        }
    }

    delay(1);
}

Debug Message

rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1288
load:0x40078000,len:13856
load:0x40080400,len:4
ho 8 tail 4 room 4
load:0x40080404,len:3048
entry 0x40080590
ETH Started
Starting the modem. It might take a while!
WiFi Connected
ETH Connected
ETH Got IP: 'eth0'
eth0: <UP,100M,FULL_DUPLEX,AUTO,ADDR:0x1> (DHCPC,GARP,IP_MOD)
      ether FE:B4:67:D7:07:00
      inet 192.168.208.194 netmask 255.255.255.0 broadcast 192.168.208.255
      gateway 192.168.208.1 dns 192.168.208.1

PPP Started
Manufacturer: SIMCOM_Ltd
Model: SIMCOM_SIM800L
IMEI: 866262035775245
Connecting to GSM Network
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Failed to connect to internet!
Failed to connect to internet!
Failed to connect to internet!
MQTT connection failed, rc= -2
******************************************************
Changing Interface....
*sta: <UP,BehamadModem,CH:11,RSSI:-34,N,WPA2_PSK> (DHCPC,GARP,IP_MOD,V6_REP)
      ether FC:B4:67:D7:07:00
      inet 192.168.199.229 netmask 255.255.255.0 broadcast 192.168.199.255
      gateway 192.168.199.1 dns 192.168.208.1

ppp: <DOWN,RSSI:20,BER:0> (,PPP)
      ether 00:00:00:00:00:00
      inet 0.0.0.0 netmask 255.255.255.255 broadcast 0.0.0.0
      gateway 0.0.0.0 dns 192.168.208.1

eth0: <UP,100M,FULL_DUPLEX,AUTO,ADDR:0x1> (DHCPC,GARP,IP_MOD)
      ether FE:B4:67:D7:07:00
      inet 192.168.208.194 netmask 255.255.255.0 broadcast 192.168.208.255
      gateway 192.168.208.1 dns 192.168.208.1

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

me-no-dev commented 4 days ago

it's up to you to manage your interfaces. You have methods to check which one is connected and to set it as default outgoing interface. You have events, you can implement that there. I'm not sure that we need to implement something more than that.

BluesBilly commented 2 days ago

if (NetInterface == "WIFI") { WiFi.STA.setDefault(); } else if (NetInterface == "PPP") { PPP.setDefault(); } else if (NetInterface == "ETH") { ETH.setDefault(); }

JAndrassy commented 2 days ago

@BluesBilly you meant to use setDefault()?

MehdiSadeghii commented 1 day ago

if (NetInterface == "WIFI") { WiFi.STA.setDefault(); } else if (NetInterface == "PPP") { PPP.setDefault(); } else if (NetInterface == "ETH") { ETH.setDefault(); }

Thanks Problem Solved..

MehdiSadeghii commented 1 day ago

it's up to you to manage your interfaces. You have methods to check which one is connected and to set it as default outgoing interface. You have events, you can implement that there. I'm not sure that we need to implement something more than that.

Yeah You're correct. it was my confusion about managing interfaces. I thought that I have to manage it using mid level APIs but now I see it's easier than I thought. Thanks a lot .