Failed to configure Ethernet (with static IP)

Hello everyone, I am new to Arduino, and I am facing some issues regarding my Ethernet configuration. I am met with a "Failed to configure Ethernet with static IP" on the serial monitor. I would really appreciate any kind of help. I will provide my entire code/sketch below. Thank you in advance! :slight_smile:

#include <ETH.h>
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
#include <WiFi.h>
#include <vector>

// GPIO pin definitions for relays
const int RELAY_POSITIVE = 26;  // Positive relay GPIO
const int RELAY_NEGATIVE = 27;  // Negative relay GPIO

AsyncWebServer server(80);
WiFiClient client;  // Ethernet client for SCPI commands

// Static IP configuration
IPAddress ip(192, 168, 1, 100);      // Static IP address
IPAddress gateway(192, 168, 1, 1);   // Gateway IP (adjust as needed)
IPAddress subnet(255, 255, 255, 0);  // Subnet mask

// Structure to hold parsed command data
struct ControlCommand {
    String type;      // Command type (e.g., "UI", "I", "DELAY", "CCD", "RUN", "STANDBY")
    float value;      // Value associated with the command
};

std::vector<ControlCommand> commands;  // List of commands

// Function declarations
void setupRelays();
void setPolarity(int direction);
void sendSCPICommand(String command);
void handleSCPIError(int errorCode);
void sendCurrentCommand(float current);
void sendVoltageCommand(float voltage);
std::vector<ControlCommand> parseFile(const char* filepath);
void executeSequence(std::vector<ControlCommand> commands);
void handleFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final);
void logMessage(const String& message);

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

    // Initialize Ethernet with static IP
    ETH.begin();
    
    // Optionally, set Ethernet pins if needed
    // Ethernet.init(5); // Uncomment and set the correct GPIO pin if necessary

    if (!ETH.config(ip, gateway, subnet)) {
        Serial.println("Failed to configure Ethernet with static IP");
        return;
    } else {
        Serial.println("Ethernet configured successfully.");
    }

    // Wait for Ethernet link
    while (!ETH.linkUp()) {
        delay(1000);
        Serial.println("Waiting for Ethernet...");
    }
    Serial.println("Connected to Ethernet with IP: " + ETH.localIP().toString());

    setupRelays();

    // Serve index.html
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send(LittleFS, "/index.html", "text/html");
    });

    // Handle file uploads
    server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) {
        request->send(200, "text/plain", "File Uploaded Successfully");
    }, handleFileUpload);

    // Start sequence endpoint
    server.on("/start", HTTP_GET, [](AsyncWebServerRequest *request) {
        commands = parseFile("/control.txt");
        executeSequence(commands);
        request->send(200, "text/plain", "Sequence started.");
    });

    server.begin();
}

void loop() {
    // Event-driven architecture; no operations in loop
}

// Relay setup
void setupRelays() {
    pinMode(RELAY_POSITIVE, OUTPUT);
    pinMode(RELAY_NEGATIVE, OUTPUT);
    digitalWrite(RELAY_POSITIVE, LOW);
    digitalWrite(RELAY_NEGATIVE, LOW);
}

// File upload handler
void handleFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
    if (!index) {
        Serial.printf("UploadStart: %s\n", filename.c_str());
        request->_tempFile = LittleFS.open("/control.txt", "w");
    }
    if (len) {
        request->_tempFile.write(data, len);
    }
    if (final) {
        Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index + len);
        request->_tempFile.close();
    }
}

// Parse command file
std::vector<ControlCommand> parseFile(const char* filepath) {
    std::vector<ControlCommand> commands;
    File file = LittleFS.open(filepath, "r");
    if (!file) {
        Serial.println("Failed to open file for reading");
        return commands;
    }

    while (file.available()) {
        String line = file.readStringUntil('\n');
        line.trim();
        if (line.startsWith("UI")) {
            float value = line.substring(3).toFloat();
            commands.push_back({"UI", value});
        } else if (line.startsWith("I")) {
            float value = line.substring(2).toFloat();
            commands.push_back({"I", value});
        } else if (line.startsWith("DELAY")) {
            float delayTime = line.substring(6).toFloat();
            commands.push_back({"DELAY", delayTime});
        } else if (line.startsWith("CCD")) {
            int direction = line.substring(4) == "+" ? 1 : -1;
            commands.push_back({"CCD", (float)direction});
        } else if (line.startsWith("RUN")) {
            commands.push_back({"RUN", 0});
        } else if (line.startsWith("STANDBY")) {
            commands.push_back({"STANDBY", 0});
        }
    }
    file.close();
    return commands;
}

// Set polarity
void setPolarity(int direction) {
    if (direction == 1) {
        digitalWrite(RELAY_POSITIVE, HIGH);
        digitalWrite(RELAY_NEGATIVE, LOW);
    } else if (direction == -1) {
        digitalWrite(RELAY_POSITIVE, LOW);
        digitalWrite(RELAY_NEGATIVE, HIGH);
    }
}

// Send SCPI command
void sendSCPICommand(String command) {
    if (client.connect("169.254.0.0", 24)) {
        client.println(command);
        delay(100);
        String response = client.readStringUntil('\n');
        if (response.startsWith("-")) {  // Error response
            int errorCode = response.toInt();
            handleSCPIError(errorCode);
        }
        client.stop();
    } else {
        Serial.println("Failed to connect to the power supply.");
    }
}

// Handle SCPI errors
void handleSCPIError(int errorCode) {
    switch (errorCode) {
        case 0:
            Serial.println("No error.");
            break;
        case -100:
            Serial.println("Command error: Command unknown.");
            break;
        case -102:
            Serial.println("Syntax error: Command syntax wrong.");
            break;
        case -108:
            Serial.println("Parameter not allowed.");
            break;
        case -200:
            Serial.println("Execution error: Command could not be executed.");
            break;
        case -201:
            Serial.println("Invalid while in local mode.");
            break;
        case -220:
            Serial.println("Parameter error: Wrong parameter used.");
            break;
        case -221:
            Serial.println("Settings conflict.");
            break;
        case -222:
            Serial.println("Data out of range.");
            break;
        case -223:
            Serial.println("Too much data.");
            break;
        case -224:
            Serial.println("Illegal parameter value.");
            break;
        case -225:
            Serial.println("Out of memory.");
            break;
        case -999:
            Serial.println("Safety OVP triggered. Please power cycle the device.");
            break;
        default:
            Serial.println("Unknown error: " + String(errorCode));
    }
}

// Execute sequence
void executeSequence(std::vector<ControlCommand> commands) {
    for (ControlCommand cmd : commands) {
        if (cmd.type == "UI") {
            sendVoltageCommand(cmd.value);
        } else if (cmd.type == "I") {
            sendCurrentCommand(cmd.value);
        } else if (cmd.type == "DELAY") {
            delay((int)(cmd.value * 1000));
        } else if (cmd.type == "CCD") {
            setPolarity((int)cmd.value);
        } else if (cmd.type == "RUN") {
            sendSCPICommand("OUTP 1");
        } else if (cmd.type == "STANDBY") {
            sendSCPICommand("OUTP 0");
        }
    }
}

// Send current command
void sendCurrentCommand(float current) {
    String command = "ISET " + String(current, 2);
    sendSCPICommand(command);
}

// Send voltage command
void sendVoltageCommand(float voltage) {
    String command = "VSET " + String(voltage, 2);
    sendSCPICommand(command);
}

// Log messages for debugging
void logMessage(const String& message) {
    Serial.println(message);
}

have a read of how-to-get-the-best-out-of-this-forum
in particular:
what host microcontroller are you using? e.g. UNO, Mega, ESP32, RP2040???
what ethernet board are you using? give a link or a photo?
how have you connected the Ethernet module to the host?
did you test the Ethernet module in a separate program before connected any other devices?

I am using the Olimex ESP32-EVB. The Ethernet board is: tp-link, model: TL-SG108. I am using an Ethernet cable (if that is what you are asking). I am not sure I understand the last question, could you give me an example please?

when you get a new device/module/sensor etc it is wise to carry out initial testing in a separate program (with no other devices connected or enabled if possible)
this ensures that you can program and use the device before attempting to add other devices which may cause problems
most libraries come with test examples to check functionality, e.g. under File>Examples

have a look at the FAQ in the ESP32-EVB documentation which suggests "for LAN8720 try adding delay () after Serial.begin()"

you could try my EthernetESP32 library which is much to the Arduino Ethernet library

I see, thank you!

For some reason I cannot install your library on Arduino IDE. I am trying to do so on GitHub. Hopefully it works.

Okay I installed the file, however I am a bit confused as to how I am suppossed to include the EthernetESP32.h file, I am met with a red error saying: "No such file or directory."

I know these questions might sound silly but I only started working on Arduino about a week ago, so I would greately appreciate your help!

A question to be asked right up front is why do you want a static IP address? If all you want is for the board to get the same IP address every time it connects to your router, it's preferable to handle that in the router itself. In the router's configuration web page, configure it so that the board's MAC address is always assigned the same IP address. Then just let the board connect via DHCP.

I see, thank you!

install the library in Library Manager in the IDE

Hello.
Here is an example of how I handle Ethernet connection on the Olimex ESP32-EVB, without the use of external libraries. I'm only using WiFi.h and ETH.h:

// connection.h

#ifndef CONNECTION_H
#define CONNECTION_H

#include <Arduino.h>
#include <WiFi.h>
#include <ETH.h>

// Function prototypes
void WiFiEvent(WiFiEvent_t event);
void startEthernetConnection();

#endif // CONNECTION_H
// connection.cpp

#include "connection.h"

static bool eth_connected = false; // Track Ethernet connection status

void WiFiEvent(WiFiEvent_t event)
{
  switch (event)
  {
  case ARDUINO_EVENT_ETH_START:
    Serial.println(F("Ethernet Started"));
    if (!ETH.setHostname("Metrici-MultiController-Eth"))
    {
      Serial.println(F("Failed to set Ethernet hostname"));
    }
    break;
  case ARDUINO_EVENT_ETH_CONNECTED:
    Serial.println(F("Ethernet Connected"));
    break;
  case ARDUINO_EVENT_ETH_GOT_IP:
    eth_connected = true;
    Serial.print(F("Ethernet MAC: "));
    Serial.print(ETH.macAddress());
    Serial.print(F(", IP: "));
    Serial.print(ETH.localIP());
    if (ETH.fullDuplex())
    {
      Serial.print(F(", FULL_DUPLEX"));
    }
    Serial.print(F(", "));
    Serial.print(ETH.linkSpeed());
    Serial.println(F(" Mbps"));
    break;
  case ARDUINO_EVENT_ETH_DISCONNECTED:
    Serial.println(F("Ethernet Disconnected"));
    eth_connected = false;
    break;
  case ARDUINO_EVENT_ETH_STOP:
    Serial.println(F("Ethernet Stopped"));
    eth_connected = false;
    break;
  default:
    break;
  }
}

void startEthernetConnection()
{
  // Register the Ethernet event handler
  WiFi.onEvent(WiFiEvent);

  // Configure the static IP
  IPAddress local_IP(192, 168, 100, 10); // Static IP
  IPAddress gateway(192, 168, 100, 1);   // Gateway
  IPAddress subnet(255, 255, 255, 0);    // Subnet mask
  IPAddress primaryDNS(8, 8, 8, 8);      // Primary DNS
  IPAddress secondaryDNS(8, 8, 4, 4);    // Secondary DNS (optional)


  // Start Ethernet connection
  ETH.begin();
  delay(1000);
  // Set the static IP configuration
  if (!ETH.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS))
  {
    Serial.println(F("Failed to configure Ethernet with static IP"));
  }

  // Wait up to 20 seconds for a connection
  int attempts = 0;
  while (!eth_connected && attempts < 20)
  {
    attempts++;
    delay(1000);
    Serial.println("[" + String(attempts) + "] - Attempting Ethernet Connection...");
  }

  // Check if connection was successful
  if (!eth_connected)
  {
    Serial.println("Failed to connect to Ethernet.");
  }
}

Then call startEthernetConnection() in void setup().

ETH.begin() must always be called before ETH.config() because it needs to have an actual connection in order to be able to configure it.
This does not apply to an WiFi connection. The WiFi Connection can be configured before starting it. It is how the arduino-esp32 core works.

Also, please notice the delay used after ETH.begin(). The actual Ethernet connection is not instant and I found it better to wait for the Ethernet connection to start properly.

1 Like

Thank you so much! :smiley: