OPTA (RS485) Webserver

Hello Arduino Community,

I'm experiencing a challenge with my Arduino OPTA board. I've been trying to build a simple web server to control LEDs and outputs, using some code examples from this forum.

However, I'm encountering a problem: each time I run the code, the RED LED above the RESET button on my OPTA starts blinking. This blinking LED seems to signal some kind of error, but I'm unable to pinpoint the exact issue. Here's what I've done so far:

  1. Adapted web server example code from the forum for my project.
  2. Made necessary modifications for controlling LEDs and outputs.
  3. On execution, the RED LED begins to blink, and the setup doesn't work as expected.

Has anyone else experienced this blinking RED LED issue on the Arduino OPTA while running a web server or similar projects? How did you manage to resolve it?

I'm looking for any advice, troubleshooting tips, or relevant experiences that could help me understand and fix this problem.

Thanks a lot for your assistance!

with the help of SimpleWebServer example for Portenta H7 in Arduino Pro Tutorials and the help of ChatGPT, i managed to create a working code if case someone is interessted.

#include <Ethernet.h>

EthernetServer server(80);

const int ledPins[] = {LED_RELAY1, LED_RELAY2, LED_RELAY3, LED_RELAY4}; // Pins for LEDs LED_RELAY1 to LED_RELAY4
const int relayPins[] = {RELAY1, RELAY2, RELAY3, RELAY4}; // Pins for Relays RELAY1 to RELAY4
boolean ledStates[] = {LOW, LOW, LOW, LOW}; // Initial LED states
boolean relayStates[] = {LOW, LOW, LOW, LOW}; // Initial Relay states

void setup() {
  Serial.begin(115200); // Initialize serial communication for debugging

  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(ledPins[i], ledStates[i]);
    digitalWrite(relayPins[i], relayStates[i]);
  }

  Ethernet.begin();
  server.begin();
  Serial.print("IP: ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  EthernetClient client = server.available();

  if (client) {
    serveWebpage(client);
  }
}

void serveWebpage(EthernetClient client) {
  String httpRequest = "";

  // Read the entire HTTP request into a string
  while (client.connected()) {
    if (client.available()) {
      char c = client.read();
      httpRequest += c;

      // Check for the end of the HTTP request
      if (httpRequest.endsWith("\r\n\r\n")) {
        break;
      }
    }
  }

  // Check for Relay and LED control requests
  for (int i = 0; i < 4; i++) {
    String ledOn = "GET /H" + String(i);
    String ledOff = "GET /L" + String(i);

    if (httpRequest.indexOf(ledOn) != -1) {
      digitalWrite(relayPins[i], HIGH); // Turn on the Relay
      digitalWrite(ledPins[i], HIGH); // Turn on the LED
      ledStates[i] = HIGH;
      relayStates[i] = HIGH;
    } else if (httpRequest.indexOf(ledOff) != -1) {
      digitalWrite(relayPins[i], LOW); // Turn off the Relay
      digitalWrite(ledPins[i], LOW); // Turn off the LED
      ledStates[i] = LOW;
      relayStates[i] = LOW;
    }
  }

  // Generate the HTML response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println();
  client.println("<html><body>");
  client.println("<h1>Webserver LED Example</h1>");
  client.println("<p>Use Edge or Safari Browser. Code seeme to hang when using Google Chrome Browser</p>");

  // Define labels
  String txtLabels[] = {"Relay1", "Relay2", "Relay3", "Relay4"};

  // Generate buttons
  for (int i = 0; i < 4; i++) {
    client.println("<div style=\"display: flex; flex-direction: row; align-items: center;\">");
    client.print("<h2 style=\"font-size: 24px;\">");
    client.print(txtLabels[i]); // Display the label
    client.println("</h2>");
    
    // Add a green or red circle based on LED state
    if (ledStates[i] == HIGH) {
      client.println("<div style=\"width: 20px; height: 20px; background-color: green; border-radius: 50%; margin-left: 10px;\"></div>");
    } else {
      client.println("<div style=\"width: 20px; height: 20px; background-color: red; border-radius: 50%; margin-left: 10px;\"></div>");
    }
    
    client.println("</div>");
    client.println("<div style=\"display: flex; flex-direction: row; align-items: center;\">");
    client.println("<a href=\"/H");
    client.print(i);
    client.print("\" style=\"font-size: 20px;\">ON</a> <span style=\"margin-right: 10px;\"></span> <a href=\"/L");
    client.print(i);
    client.print("\" style=\"font-size: 20px;\">OFF</a>");
    client.println("</div>");
  }

  client.println("</body></html>");
}

The only thing i noticed, it's working fine when using Safari browser on my ipad. When using Google Chrome on ipad, webpage refresh is pretty slow and often i get "Page could not be loaded". Any ideas?

1 Like

Hi Muerzi,
I am working with Arduino Opta connected with an Ethernet cable. I have also installed a web server very similar as yours. And I have the same problem or at least I think so. When I access Opta with Firefox, it works fine. But when I try with Google Chrome, the flow control gets stuck when I close the connection ( inside "client.stop()") until the watchdog resets the Opta. I have no idea how to fix it.

After searching the web i found out, that the favicon (Image left of URL in adressbar) is causing that problem. Chrome is waitng for a favicon but arduino is not providing that.
if your html code provided by your OPTA looks like this, it will fix the issue:

client.println("<html><head><title>Example Code</title>");
client.println("<link rel='icon' href='data:;base64,iVBORw0KGgo='></head>");
client.println("<body>");

included in head tag must be ""

let me know if this also fix your issue

Hi Muerzi, thank you very much for your help.
I have tried the solution you suggested:

  client.println ("HTTP/1.1 200 OK");
  client.println ("Content-Type: text/html");
  client.println("Connection: close"); 
  client.println ();
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.println("<head><title>Hello world </title>");
  client.print ("<link rel='icon' href='data:;base64,iVBORw0KGgo='>");
  client.println("</head>"); 
  client.println("<body>");
  client.println("<h2>Hello world</h2>");
  client.println("</body>");
  client.println("</html>");

I have also tried with this other line instead:
client.println("<link rel='icon' href='http://google.com/favicon.ico' type='image/x-icon'>");
But the problem continues: when I try the server with Firefox, it works fine. But when I try with Google Chrome, the control gets stuck and the Opta ends up falling.
I keep looking at it. I need to fix it.

Try the following: Open Chrome, Press F12 on choose Network Tab, try to access webpage of your arduino and post the result from Debugconsole (include Waterfall diagram)

Hi Muerzi, and thanks again.
I have done it.
I have access the arduino webpage with this command:
this.document.location = "http://192.168.1.177"
from the DebugConsole in Chrome.
Seems there is no errors under Chrome, but when I access like this, the Opta stops working.
I am trying to post the result as a image (don`t know if I am doing this well)


This is the sketch I am testing with:

#include <Ethernet.h>

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);  // Comprobar que la IP esta vacante en tu red local
EthernetServer server(80);

EthernetClient clients[8];
bool ledLights = false;

void setup() {
  delay (5000);  // Just in case
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  while (!Serial) ;

  pinMode (LED_D0, OUTPUT);
  digitalWrite (LED_D0, HIGH);
  ledLights = true;

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); 
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }
  server.begin(); // start listening for clients

  Serial.println ("**************************************");
  Serial.println (Ethernet.localIP());
}

void loop() {
  EthernetClient client = server.available();

  if (client) {
    Serial.println (""); Serial.println ("new client");
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == 'n' && currentLineIsBlank) {
 
            // Answer the client
            client.println ("HTTP/1.1 200 OK");
            client.println ("Content-Type: text/html");
            client.println("Connection: close"); 
            client.println ();
            client.println("<!DOCTYPE HTML>");
            client.println("<html>");
            client.println("<head><title>Hello world </title>");
            client.print ("<link rel='icon' href='data:;base64,iVBORw0KGgo='>");
            client.println("</head>"); 
            client.println("<body>");
            client.println("<h2>Hello world</h2>");
            client.println("</body>");
            client.println("</html>");
            break;
        }

        if (c == 'n') {
          currentLineIsBlank = true;
        } else if (c != 'r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1); 
    client.stop(); // close conection
  }
  
  if (ledLights) {
    digitalWrite (LED_D0, LOW);
    ledLights = false;
  } else {
    digitalWrite (LED_D0, HIGH);
    ledLights = true;
  }
  delay (100);
}

The OPTA is connected via Ethernet cable.
In summary, when I access the arduino website from Firefox it works fine, but when accessing with Chrome the OPTA blocks (the led stops blinking).
Again thank you for your help.

Hi,
I have been studding this issue. The behavior of Google Chrome is curious regarding how the html frame is constructed. Chrome usually makes 2 calls, the second asking for the favicon. Regarding to the head tag I have observed this:

client.println ("<head>");
client.println ("<title>Arduino web server</title>");
client.println ("<link rel='icon' href='data:;base64,iVBORw0KGgo='>");
client.println ("</head>");
  • If you write "Arduino web server " (with a blank after "server"), connection is blocked.
  • Chrome makes 2 calls, the second asking for the favicon. The second connection is blocked.
  • If you try this instead:
    client.println ("<link rel='google icon' href='http://google.com/favicon.ico' type='image/x-icon'>");
  • or this:
    client.println ("<link rel='world icon' href='data:,'>");
  • ... the result is the same: 2 calls and the second one is blocked.
  • The simplest thing is to skip the favicon.ico . Chrome makes 2 calls but at least it doesn't it does not get stuck.
  • With firefox browser, none of these problems appear.
    Since I need the main thread to run smoothly, I have prepared a new sketch putting the task that attends the web client inside a thread running in background:
#include <SPI.h>
#include <PortentaEthernet.h>
#include <Ethernet.h>

IPAddress ip(192, 168, 1, 180);
EthernetServer server(80);

static rtos::Thread *backgroundThread = NULL;  // real time operating system
rtos::Thread::State threadState;

EthernetClient client;
unsigned long timeClient = 0;
bool led0 = false;

void setup() {
  delay (5000);

  Serial.begin(9600);
  while (!Serial) {;}
  Serial.println("Ethernet WebServer in a thread");

  pinMode (LED_D0, OUTPUT);
  digitalWrite (LED_D0, LOW);
  led0 = false;
   
  Ethernet.begin(ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin ();
  Serial.print ("server is at ");
  Serial.println (Ethernet.localIP());
}


void loop() {
  EthernetLoop ();  // listen for incoming clients

  if (led0) {
    digitalWrite (LED_D0, LOW);
    led0 = false;
  } else {
    digitalWrite (LED_D0, HIGH);
    led0 = true;
  }
  delay (100);
}

void EthernetLoop () {
  if (backgroundThread != NULL) {  // serving a client
    if (millis() - timeClient > 5000) {  // audit time
      threadState = backgroundThread->get_state();
      if (threadState != rtos::Thread::State::Deleted) {  // kill the thread
        backgroundThread->terminate();
        delete backgroundThread; backgroundThread = NULL;
        Serial.println ("Webserver blocked, kill the thread");
      }
    } else {  // Still serving a client?
      threadState = backgroundThread->get_state();
      if (threadState == rtos::Thread::State::Deleted) {
        delete backgroundThread; backgroundThread = NULL;
        Serial.println ("The thread is over");
      } else {  // The thead is running and on time
        Serial.print (".");
        return; 
      }
    }
  }

  // Available for new clients 
  client = server.available();
  if (client) {
    Serial.println ("Serving a client");
    
    timeClient = millis();
    backgroundThread = new rtos::Thread;
    backgroundThread->start (Background);
  }
}

void Background () {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          // google Chrome call the server twice (favicon)
          client.println ("<head>");
          client.println ("<title>Arduino web server</title>");
          // client.println ("<link rel='icon' href='data:;base64,iVBORw0KGgo='>");   // Chrome makes 2 calls, the second blocked
          // client.println ("<link rel='google icon' href='http://google.com/favicon.ico' type='image/x-icon'>");   // Chrome makes 2 calls, the second blocked
          // client.println ("<link rel='world icon' href='data:,'>");  // Chrome makes 2 calls, the second blocked 
          client.println ("</head>");

          client.println ("<body>"); 
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("<h3>"); 
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("</h3>");
          }
          client.println ("</body>"); 
          client.println ("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);  // give the web browser time to receive the data
    client.stop();  // close the connection:
    Serial.println("client disconnected");
    Serial.println ("Serving a client is over");
}

In this sketch the main loop only blinks the LED_0, but always with rhythm, regardless of the requests that the OPTA is attending to. If the web client gets stuck, the background thread will be deleted after 5 seconds. This sketch works fine for OPTA connected via Ethernet cable. I hope this solution helps others, I have wasted a lot of time analyzing this issue.

1 Like