Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
liamcharmer opened this issue Nov 3, 2024 · 0 comments

Comments

@liamcharmer
Copy link

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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant