Skip to content

Web socket server keeps rebooting when attempting to start the web socket server after establishing ethernet connection #915

@liamcharmer

Description

@liamcharmer

So it's quite weird. When the web socket server starts. It reboots the arduino. Can this library work with ethernet?

I am using;

Arduino Nano ESP32 with Headers [ABX00083] - ESP32-S3, USB-C, Wi-Fi, Bluetooth, HID Support, MicroPython Compatible
https://www.amazon.co.uk/dp/B0C947BHK5?ref=ppx_yo2ov_dt_b_fed_asin_title

and
AZDelivery ENC28J60 Ethernet Shield LAN Network Module compatible with Arduino including E-Book!
https://www.amazon.co.uk/dp/B07D8SV85Q?ref=ppx_yo2ov_dt_b_fed_asin_title

#include <EthernetENC.h>
#include <WebSocketsServer.h>  // Links2004 WebSocket library
#include <ArduinoJson.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define LED_PIN 46
#define OLED_RESET -1
#define I2C_SDA 5
#define I2C_SCL 4

// ENC28J60 pins for SPI communication
#define CS_PIN 7
#define MISO_PIN 12
#define MOSI_PIN 11
#define SCK_PIN 13

// Network configuration
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 177);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);

WebSocketsServer webSocket = WebSocketsServer(80);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
bool displayAvailable = false;

#define MAX_CLIENTS 10
#define MAX_ROOMS 5
#define MAX_LOG_LINES 5
#define MAX_PLAYERS_PER_ROOM 4

// Message queue structure
#define MAX_QUEUE_SIZE 10
struct QueuedMessage {
  String message;
  bool used;
};

struct VirtualLockbox {
  bool isLocked;
  int deviceCount;
  bool isInitialized;
};

struct Room {
  String roomId;
  VirtualLockbox lockbox;
  bool isActive;
};

struct MessageQueue {
  QueuedMessage messages[MAX_QUEUE_SIZE];
  int head;
  int tail;
};

MessageQueue messageQueues[MAX_CLIENTS];
Room rooms[MAX_ROOMS];

// Circular buffer for log messages
String logLines[MAX_LOG_LINES];
int currentLogLine = 0;

struct WebSocketClient {
  uint8_t num;  // WebSocket client number
  String clientId;
  String roomId;
  bool isHost;
  bool isExternal;
  bool isPlayer;
  String label;
};

WebSocketClient wsClients[MAX_CLIENTS];
uint8_t clientIds[MAX_ROOMS][MAX_CLIENTS];
uint8_t clientCount[MAX_ROOMS] = {0};
uint8_t playerCount[MAX_ROOMS] = {0};

// Queue management functions
void initQueue(int clientIndex) {
  messageQueues[clientIndex].head = 0;
  messageQueues[clientIndex].tail = 0;
  for (int i = 0; i < MAX_QUEUE_SIZE; i++) {
    messageQueues[clientIndex].messages[i].used = false;
  }
}

void queueMessage(int clientIndex, const String& message) {
  MessageQueue& queue = messageQueues[clientIndex];
  int nextTail = (queue.tail + 1) % MAX_QUEUE_SIZE;
  
  if (nextTail != queue.head) {
    queue.messages[queue.tail].message = message;
    queue.messages[queue.tail].used = true;
    queue.tail = nextTail;
  }
}

void setLockboxLED(bool locked) {
  digitalWrite(LED_PIN, !locked ? HIGH : LOW);
  addLog(String("LED ") + (locked ? "ON" : "OFF"));
}

void sendQueuedMessages(uint8_t num) {
  int clientIndex = -1;
  for (int i = 0; i < MAX_CLIENTS; i++) {
    if (wsClients[i].num == num) {
      clientIndex = i;
      break;
    }
  }
  
  if (clientIndex != -1) {
    MessageQueue& queue = messageQueues[clientIndex];
    while (queue.head != queue.tail) {
      if (queue.messages[queue.head].used) {
        webSocket.sendTXT(num, queue.messages[queue.head].message);
        queue.messages[queue.head].used = false;
      }
      queue.head = (queue.head + 1) % MAX_QUEUE_SIZE;
    }
  }
}

void addLog(const String& message) {
  Serial.println(message);
  
  logLines[currentLogLine] = message;
  currentLogLine = (currentLogLine + 1) % MAX_LOG_LINES;
  
  if (displayAvailable) {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    
    display.setCursor(0, 0);
    display.print("IP: ");
    display.println(Ethernet.localIP());
    display.drawLine(0, 9, SCREEN_WIDTH - 1, 9, WHITE);
    
    int y = 11;
    for (int i = 0; i < MAX_LOG_LINES; i++) {
      int index = (currentLogLine - 1 - i + MAX_LOG_LINES) % MAX_LOG_LINES;
      if (!logLines[index].isEmpty()) {
        display.setCursor(0, y);
        String truncated = logLines[index];
        if (truncated.length() > 21) {
          truncated = truncated.substring(0, 18) + "...";
        }
        display.println(truncated);
        y += 10;
      }
    }
    
    display.display();
  }
}

int findRoomIndex(const String& roomId) {
  for (int i = 0; i < MAX_ROOMS; i++) {
    if (clientCount[i] > 0 && wsClients[clientIds[i][0]].roomId == roomId) {
      return i;
    }
  }
  for (int i = 0; i < MAX_ROOMS; i++) {
    if (clientCount[i] == 0) {
      return i;
    }
  }
  return -1;
}

void broadcastToRoom(uint8_t sender, String& message) {  // Changed to non-const reference
    String roomId;
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (wsClients[i].num == sender) {
            roomId = wsClients[i].roomId;
            break;
        }
    }
    
    if (!roomId.isEmpty()) {
        int roomIndex = findRoomIndex(roomId);
        if (roomIndex != -1) {
            for (int i = 0; i < clientCount[roomIndex]; i++) {
                uint8_t clientNum = wsClients[clientIds[roomIndex][i]].num;
                webSocket.sendTXT(clientNum, message);
            }
        }
    }
}

void initializeRoomLockbox(const String& roomId) {
  int roomIndex = findRoomIndex(roomId);
  if (roomIndex != -1) {
    rooms[roomIndex].roomId = roomId;
    rooms[roomIndex].isActive = true;
    rooms[roomIndex].lockbox = {false, 0, true};
    
    DynamicJsonDocument doc(256);
    doc["type"] = "lockbox_init";
    String message;
    serializeJson(doc, message);
    
    for (int i = 0; i < clientCount[roomIndex]; i++) {
      uint8_t clientNum = wsClients[clientIds[roomIndex][i]].num;
      webSocket.sendTXT(clientNum, message);
    }
    
    addLog("Room " + roomId + " created with virtual lockbox");
  }
}

void cleanupRoomLockbox(const String& roomId) {
  int roomIndex = findRoomIndex(roomId);
  if (roomIndex != -1) {
    rooms[roomIndex].isActive = false;
    rooms[roomIndex].lockbox = {false, 0, false};
    setLockboxLED(false);
    addLog("Room " + roomId + " destroyed, lockbox cleaned up");
  }
}

void handleLockboxMessage(uint8_t num, const String& type, const JsonObject& data) {
  String roomId;
  for (int i = 0; i < MAX_CLIENTS; i++) {
    if (wsClients[i].num == num) {
      roomId = wsClients[i].roomId;
      break;
    }
  }
  
  int roomIndex = findRoomIndex(roomId);
  if (roomIndex == -1 || !rooms[roomIndex].isActive) return;
  
  VirtualLockbox& lockbox = rooms[roomIndex].lockbox;
  
  if (type == "lockbox_init") {
    lockbox.deviceCount = 0;
    lockbox.isLocked = false;
    lockbox.isInitialized = true;
    setLockboxLED(false);
    
    DynamicJsonDocument doc(256);
    doc["type"] = "lockbox_init";
    String message;
    serializeJson(doc, message);
    
    broadcastToRoom(num, message);
    addLog("Lockbox initialized in room: " + roomId);
  }
  else if (type == "lockbox_device_added") {
    if (!lockbox.isInitialized) return;
    
    lockbox.deviceCount++;
    
    DynamicJsonDocument doc(256);
    doc["type"] = "lockbox_device_added";
    doc["data"]["deviceCount"] = lockbox.deviceCount;
    String message;
    serializeJson(doc, message);
    
    broadcastToRoom(num, message);
    addLog("Device added to lockbox in room " + roomId + ": " + String(lockbox.deviceCount));
    
    if (lockbox.deviceCount >= 4 && !lockbox.isLocked) {
      lockbox.isLocked = true;
      setLockboxLED(true);
      
      DynamicJsonDocument lockDoc(256);
      lockDoc["type"] = "devices_locked";
      lockDoc["data"]["locked"] = true;
      String lockMessage;
      serializeJson(lockDoc, lockMessage);
      
      broadcastToRoom(num, lockMessage);
      addLog("Lockbox locked in room: " + roomId);
    }
  }
  else if (type == "unlock_devices") {
    if (!lockbox.isInitialized) return;
    
    lockbox.isLocked = false;
    setLockboxLED(false);
    
    DynamicJsonDocument doc(256);
    doc["type"] = "unlock_devices";
    String message;
    serializeJson(doc, message);
    
    broadcastToRoom(num, message);
    addLog("Lockbox unlocked in room: " + roomId);
  }
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
    switch(type) {
        case WStype_DISCONNECTED: {
            Serial.printf("[WebSocket] Client #%u Disconnected\n", num);
            String clientId;
            String roomId;
            bool wasHost = false;
            bool wasPlayer = false;
            int clientIndex = -1;
            
            // Find the disconnected client's information
            for (int i = 0; i < MAX_CLIENTS; i++) {
                if (wsClients[i].num == num) {
                    clientId = wsClients[i].clientId;
                    roomId = wsClients[i].roomId;
                    wasHost = wsClients[i].isHost;
                    wasPlayer = wsClients[i].isPlayer;
                    clientIndex = i;
                    break;
                }
            }
            
            if (clientIndex != -1) {
                int roomIndex = findRoomIndex(roomId);
                if (roomIndex != -1) {
                    // Update player count if necessary
                    if (wasPlayer) {
                        playerCount[roomIndex]--;
                    }
                    
                    // Remove client from room's client list
                    for (int j = 0; j < clientCount[roomIndex]; j++) {
                        if (clientIds[roomIndex][j] == clientIndex) {
                            // Shift remaining clients
                            for (int k = j; k < clientCount[roomIndex] - 1; k++) {
                                clientIds[roomIndex][k] = clientIds[roomIndex][k + 1];
                            }
                            clientCount[roomIndex]--;
                            break;
                        }
                    }
                    
                    // If room is empty, clean up
                    if (clientCount[roomIndex] == 0) {
                        cleanupRoomLockbox(roomId);
                        playerCount[roomIndex] = 0;
                        addLog("Room " + roomId + " reset");
                    } else {
                        // Notify remaining clients about disconnection
                        DynamicJsonDocument doc(256);
                        doc["type"] = "user_disconnected";
                        doc["data"]["clientId"] = clientId;
                        doc["data"]["isPlayer"] = wasPlayer;
                        doc["data"]["wasHost"] = wasHost;
                        doc["data"]["playerCount"] = playerCount[roomIndex];
                        
                        String message;
                        serializeJson(doc, message);
                        
                        for (int j = 0; j < clientCount[roomIndex]; j++) {
                            uint8_t targetNum = wsClients[clientIds[roomIndex][j]].num;
                            webSocket.sendTXT(targetNum, message);
                        }
                        
                        // Reassign host if necessary
                        if (wasHost) {
                            reassignHost(roomId);
                        }
                    }
                }
                
                // Clear client data
                wsClients[clientIndex] = {0, "", "", false, false, false, ""};
                initQueue(clientIndex);
                addLog("Client disconnected: " + clientId);
            }
            break;
        }
        
        case WStype_CONNECTED: {
           Serial.printf("[WebSocket] Client #%u Connected\n", num);
            String url = String((char*)payload);
            String clientId = "";
            String roomId = "";
            bool isPlayer = false;
            String label = "";
            
            // Extract parameters from connection URL
            int clientIdStart = url.indexOf("clientId=");
            int roomIdStart = url.indexOf("roomId=");
            int isPlayerStart = url.indexOf("isPlayer=");
            int labelStart = url.indexOf("label=");
            
            if (clientIdStart != -1) {
                clientIdStart += 9; // Length of "clientId="
                int clientIdEnd = url.indexOf('&', clientIdStart);
                if (clientIdEnd == -1) clientIdEnd = url.length();
                clientId = url.substring(clientIdStart, clientIdEnd);
            }
            
            if (roomIdStart != -1) {
                roomIdStart += 7; // Length of "roomId="
                int roomIdEnd = url.indexOf('&', roomIdStart);
                if (roomIdEnd == -1) roomIdEnd = url.length();
                roomId = url.substring(roomIdStart, roomIdEnd);
            }
            
            if (isPlayerStart != -1) {
                isPlayerStart += 9; // Length of "isPlayer="
                int isPlayerEnd = url.indexOf('&', isPlayerStart);
                if (isPlayerEnd == -1) isPlayerEnd = url.length();
                String isPlayerStr = url.substring(isPlayerStart, isPlayerEnd);
                isPlayer = (isPlayerStr == "true");
            }
            
            if (labelStart != -1) {
                labelStart += 6; // Length of "label="
                int labelEnd = url.indexOf('&', labelStart);
                if (labelEnd == -1) labelEnd = url.length();
                label = url.substring(labelStart, labelEnd);
            }
            
            if (clientId.isEmpty()) {
                webSocket.disconnect(num);
                return;
            }
            
            // Check for reconnection
            bool isReconnection = false;
            int existingIndex = -1;
            for (int i = 0; i < MAX_CLIENTS; i++) {
                if (wsClients[i].num != 0 && wsClients[i].clientId == clientId) {
                    existingIndex = i;
                    isReconnection = true;
                    break;
                }
            }
            
            // Handle reconnection
            if (isReconnection) {
                addLog("Client reconnecting: " + clientId);
                wsClients[existingIndex] = {0, "", "", false, false, false, ""};
            }
            
            // Find empty slot for new connection
            int clientIndex = -1;
            for (int i = 0; i < MAX_CLIENTS; i++) {
                if (wsClients[i].num == 0) {
                    clientIndex = i;
                    break;
                }
            }
            
            if (clientIndex != -1) {
                int roomIndex = findRoomIndex(roomId);
                if (roomIndex == -1) {
                    roomIndex = findRoomIndex("");
                }
                
                if (roomIndex != -1) {
                    if (clientCount[roomIndex] == 0) {
                        initializeRoomLockbox(roomId);
                    }
                    
                    // Check player limit
                    if (isPlayer && playerCount[roomIndex] >= MAX_PLAYERS_PER_ROOM) {
                        webSocket.disconnect(num);
                        addLog("Room full - connection rejected");
                        return;
                    }
                    
                    bool isHost = (isPlayer && playerCount[roomIndex] == 0);
                    wsClients[clientIndex] = {num, clientId, roomId, isHost, false, isPlayer, label};
                    clientIds[roomIndex][clientCount[roomIndex]++] = clientIndex;
                    
                    if (isPlayer) {
                        playerCount[roomIndex]++;
                        addLog("Player count in room " + roomId + ": " + String(playerCount[roomIndex]));
                    }
                    
                    initQueue(clientIndex);
                    sendQueuedMessages(num);
                    
                    // Notify room about new connection
                    DynamicJsonDocument doc(256);
                    doc["type"] = "user_entered";
                    doc["data"]["clientId"] = clientId;
                    doc["data"]["isPlayer"] = isPlayer;
                    doc["data"]["playerCount"] = playerCount[roomIndex];
                    
                    String message;
                    serializeJson(doc, message);
                    
                    for (int i = 0; i < clientCount[roomIndex]; i++) {
                        uint8_t targetNum = wsClients[clientIds[roomIndex][i]].num;
                        if (targetNum != num) { // Don't send to the new client
                            webSocket.sendTXT(targetNum, message);
                        }
                    }
                    
                    if (isHost) {
                        notifyHostAssigned(roomId, clientId);
                    }
                    
                    addLog(String(isPlayer ? "Player" : "Spectator") + 
                          " connected: " + clientId + 
                          (isReconnection ? " (reconnected)" : ""));
                } else {
                    addLog("No room available");
                    webSocket.disconnect(num);
                }
            } else {
                addLog("Max clients reached");
                webSocket.disconnect(num);
            }
            break;
        }
        
        case WStype_TEXT: {
           Serial.printf("[WebSocket] Received text from #%u\n", num);
            String message = String((char*)payload);
            DynamicJsonDocument doc(1024);
            DeserializationError error = deserializeJson(doc, message);
            
            if (error) {
                addLog("JSON parse failed");
                return;
            }
            
            String type = doc["type"];
            
            // Handle update_socket_client_id message
            if (type == "update_socket_client_id") {
                String oldClientId = doc["data"]["oldClientId"];
                String newClientId = doc["data"]["newClientId"];
                
                for (int i = 0; i < MAX_CLIENTS; i++) {
                    if (wsClients[i].num == num && wsClients[i].clientId == oldClientId) {
                        wsClients[i].clientId = newClientId;
                        addLog("Updated client ID: " + oldClientId + " -> " + newClientId);
                        break;
                    }
                }
                return;
            }
            
            // Handle lockbox messages
            if (type == "lockbox_init" || type == "lockbox_device_added" || type == "unlock_devices") {
                handleLockboxMessage(num, type, doc["data"]);
                return;
            }
            
            // Broadcast other messages to room
            broadcastToRoom(num, message);
            break;
        }
        
        case WStype_BIN:
        case WStype_ERROR:
        case WStype_FRAGMENT_TEXT_START:
        case WStype_FRAGMENT_BIN_START:
        case WStype_FRAGMENT:
        case WStype_FRAGMENT_FIN:
        default:
            break;
    }
}

void notifyHostAssigned(const String& roomId, const String& clientId) {
  DynamicJsonDocument doc(256);
  doc["type"] = "host_assigned";
  doc["data"]["isHost"] = true;
  doc["data"]["clientId"] = clientId;

  String message;
  serializeJson(doc, message);
  
  addLog("Host: " + clientId);

  int roomIndex = findRoomIndex(roomId);
  if (roomIndex != -1) {
    for (int i = 0; i < clientCount[roomIndex]; i++) {
      uint8_t clientNum = wsClients[clientIds[roomIndex][i]].num;
      webSocket.sendTXT(clientNum, message);
    }
  }
}

void reassignHost(const String& roomId) {
  int roomIndex = findRoomIndex(roomId);
  if (roomIndex == -1 || clientCount[roomIndex] == 0) {
    return;
  }

  // Find first non-host, non-external client
  for (int i = 0; i < clientCount[roomIndex]; i++) {
    uint8_t id = clientIds[roomIndex][i];
    if (!wsClients[id].isHost && !wsClients[id].isExternal) {
      wsClients[id].isHost = true;
      notifyHostAssigned(roomId, wsClients[id].clientId);
      addLog("New host assigned: " + wsClients[id].clientId);
      break;
    }
  }
}

bool parseUrlParams(const String& url, String& clientId, String& roomId, bool& isPlayer) {
  // Example URL format: /ws?clientId=123&roomId=456&isPlayer=true
  int clientIdStart = url.indexOf("clientId=");
  int roomIdStart = url.indexOf("roomId=");
  int isPlayerStart = url.indexOf("isPlayer=");
  
  if (clientIdStart == -1 || roomIdStart == -1) {
    return false;
  }
  
  clientIdStart += 9; // Length of "clientId="
  int clientIdEnd = url.indexOf('&', clientIdStart);
  if (clientIdEnd == -1) clientIdEnd = url.length();
  clientId = url.substring(clientIdStart, clientIdEnd);
  
  roomIdStart += 7; // Length of "roomId="
  int roomIdEnd = url.indexOf('&', roomIdStart);
  if (roomIdEnd == -1) roomIdEnd = url.length();
  roomId = url.substring(roomIdStart, roomIdEnd);
  
  if (isPlayerStart != -1) {
    isPlayerStart += 9; // Length of "isPlayer="
    int isPlayerEnd = url.indexOf('&', isPlayerStart);
    if (isPlayerEnd == -1) isPlayerEnd = url.length();
    String isPlayerStr = url.substring(isPlayerStart, isPlayerEnd);
    isPlayer = (isPlayerStr == "true");
  } else {
    isPlayer = false;
  }
  
  return true;
}

bool initializeDisplay() {
  Serial.println("Attempting to initialize OLED display...");
  
  Wire.begin(I2C_SDA, I2C_SCL);
  
  Wire.beginTransmission(0x3C);
  if (Wire.endTransmission() != 0) {
    Serial.println("Display not found on I2C bus");
    return false;
  }

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
    return false;
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Initializing...");
  display.display();
  
  Serial.println("OLED display initialized successfully");
  return true;
}

bool initializeEthernet() {
  Serial.println("Initializing Ethernet...");
  
  SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
  Ethernet.init(CS_PIN);
  
  if (Ethernet.begin(mac)) {
    Serial.print("DHCP assigned IP: ");
    Serial.println(Ethernet.localIP());
    return true;
  } else {
    Serial.println("DHCP failed, trying static IP...");
    Ethernet.begin(mac, ip, gateway, subnet);
    
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield not found");
      return false;
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected");
      return false;
    }
    
    Serial.print("Static IP: ");
    Serial.println(Ethernet.localIP());
    return true;
  }
}
void setup() {
  Serial.begin(115200);
  Serial.println("Starting up...");
  
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);

  // Initialize rooms
  for (int i = 0; i < MAX_ROOMS; i++) {
    rooms[i].isActive = false;
    rooms[i].lockbox = {false, 0, false};
  }

  // Initialize client array
  for (int i = 0; i < MAX_CLIENTS; i++) {
    wsClients[i] = {0, "", "", false, false, false, ""};
    initQueue(i);
  }

  // Initialize display
  displayAvailable = initializeDisplay();
  if (!displayAvailable) {
    Serial.println("WARNING: Display initialization failed - continuing without display");
  }

  // Initialize Ethernet with verification
  if (!initializeEthernet()) {
    Serial.println("Failed to initialize Ethernet");
    digitalWrite(LED_PIN, LOW);
    return;
  }

  // Wait for Ethernet to be fully ready
  delay(1000);
  
  // Verify Ethernet status before starting WebSocket
  if (Ethernet.linkStatus() == LinkON && Ethernet.localIP()) {
    Serial.println("Ethernet is ready. Starting WebSocket server...");
    
    // Initialize WebSocket server
    webSocket.begin();
    webSocket.onEvent(webSocketEvent);
    
    addLog("WebSocket Server Ready");
    addLog("IP: " + Ethernet.localIP().toString());
    digitalWrite(LED_PIN, HIGH);  // Indicate successful setup
  } else {
    Serial.println("Ethernet not ready. Cannot start WebSocket server.");
    digitalWrite(LED_PIN, LOW);
  }
}

// Modified loop with debug prints and state tracking
void loop() {
  static unsigned long lastDebugPrint = 0;
  static bool wsActive = false;
  static int loopCount = 0;
  
  // Basic loop counter for debugging
  loopCount++;
  
  // Print debug info every 5 seconds
  if (millis() - lastDebugPrint >= 5000) {
    Serial.printf("Loop count: %d, Ethernet status: %s, IP: %s\n", 
                 loopCount,
                 Ethernet.linkStatus() == LinkON ? "ON" : "OFF",
                 Ethernet.localIP().toString().c_str());
    lastDebugPrint = millis();
    loopCount = 0;
  }

  // Check Ethernet status
  if (Ethernet.linkStatus() == LinkON && Ethernet.localIP()) {
    if (!wsActive) {
      Serial.println("Ethernet is connected, starting WebSocket server");
      webSocket.begin();
      webSocket.onEvent(webSocketEvent);
      wsActive = true;
    }
    // Only run WebSocket loop if we're properly connected
    webSocket.loop();
  } else {
    if (wsActive) {
      Serial.println("Ethernet disconnected, stopping WebSocket server");
      wsActive = false;
    }
  }
  
  // Maintain Ethernet connection
  Ethernet.maintain();
  
  // Monitor display connection
  static unsigned long lastDisplayCheck = 0;
  if (millis() - lastDisplayCheck >= 30000) {  // Check every 30 seconds
    lastDisplayCheck = millis();
    
    if (!displayAvailable) {
      Wire.beginTransmission(0x3C);
      if (Wire.endTransmission() == 0) {
        displayAvailable = initializeDisplay();
        if (displayAvailable) {
          addLog("Display connected");
        }
      }
    } else {
      Wire.beginTransmission(0x3C);
      if (Wire.endTransmission() != 0) {
        displayAvailable = false;
        Serial.println("Display disconnected");
      }
    }
  }

  // Small delay to prevent tight looping
  delay(1);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions