#include #include #include #include #define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT #define ETH_PHY_POWER 12 #include #define TRIGGER_TIMEOUT 60000 #define PIN_ACTIVATE 5 #define PIN_CLEAR 2 bool inputActive = true; bool clearActive = true; long activateTimeout = 0; int lampSockets[4] = {-1, -1, -1, -1}; static bool eth_connected = false; AsyncWebServer server(80); AsyncWebSocket ws("/ws"); String lastSent = "---"; void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { if (type == WS_EVT_CONNECT) { Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); client->printf("Client: %u", client->id()); client->ping(); } else if (type == WS_EVT_DISCONNECT) { Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id()); for (int i = 0; i < 4; i++) { if (lampSockets[i] == client->id()) { lampSockets[i] = -1; break; } } } else if (type == WS_EVT_ERROR) { Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data); } else if (type == WS_EVT_PONG) { Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : ""); } else if (type == WS_EVT_DATA) { AwsFrameInfo *info = (AwsFrameInfo *)arg; String msg = ""; if (info->final && info->index == 0 && info->len == len) { // the whole message is in a single frame and we got all of it's data Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len); if (info->opcode == WS_TEXT) { for (size_t i = 0; i < info->len; i++) { msg += (char)data[i]; } Serial.print("message: "); Serial.println(msg); } if (msg == "conlamp:0") { Serial.println("Lamp0 connected!"); lampSockets[0] = client->id(); } else if (msg == "conlamp:1") { Serial.println("Lamp1 connected!"); lampSockets[1] = client->id(); } else if (msg == "conlamp:2") { Serial.println("Lamp2 connected!"); lampSockets[2] = client->id(); } else if (msg == "conlamp:3") { Serial.println("Lamp3 connected!"); lampSockets[3] = client->id(); } } else { Serial.printf("Error: Message in multiple Frames"); } } Serial.println(); } void notFound(AsyncWebServerRequest *request) { request->send(404, "text/plain", "Not found"); } void WiFiEvent(WiFiEvent_t event) { switch (event) { case SYSTEM_EVENT_ETH_START: Serial.println("ETH Started"); ETH.setHostname("a2clcontroller"); break; case SYSTEM_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break; case SYSTEM_EVENT_ETH_GOT_IP: Serial.print("ETH MAC: "); Serial.print(ETH.macAddress()); Serial.print(", IPv4: "); Serial.print(ETH.localIP()); if (ETH.fullDuplex()) { Serial.print(", FULL_DUPLEX"); } Serial.print(", "); Serial.print(ETH.linkSpeed()); Serial.println("Mbps"); eth_connected = true; break; case SYSTEM_EVENT_ETH_DISCONNECTED: Serial.println("ETH Disconnected"); eth_connected = false; break; case SYSTEM_EVENT_ETH_STOP: Serial.println("ETH Stopped"); eth_connected = false; break; default: break; } } void setup() { Serial.begin(115200); WiFi.onEvent(WiFiEvent); ETH.begin(); pinMode(PIN_ACTIVATE, INPUT_PULLUP); pinMode(PIN_CLEAR, INPUT_PULLUP); while (!eth_connected) { delay(1000); } if (!MDNS.begin("a2clcontroller")) { Serial.println("Error setting up MDNS responder!, system halt"); while (1) { delay(1000); } } Serial.println("mDNS responder started"); ws.onEvent(onWsEvent); server.addHandler(&ws); server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { // Print a small status response page with the most important messages String statusHTML = ""; statusHTML += "

Audio2 Cabin Light System


Current Status:
"; statusHTML += ""; for (int i = 0; i < 4; i++) { statusHTML += ""; } statusHTML += "
LampStatus
Lamp "; statusHTML += String(i); statusHTML += ""; statusHTML += lampSockets[i] != -1 ? String("

Connected

") : String("

Disconnected

"); statusHTML += "

"; statusHTML += "Last Sent Status: " + lastSent + "
"; statusHTML += "Input active: "; statusHTML += inputActive ? "inactive (high)" : "active (low)"; statusHTML += "
"; statusHTML += "Input clear: "; statusHTML += clearActive ? "inactive (high)" : "active (low)"; statusHTML += "
Timeout: "; statusHTML += (activateTimeout == 0 || millis() - activateTimeout >= TRIGGER_TIMEOUT) ? "active" : "inactive"; statusHTML += "
"; request->send(200, "text/html", statusHTML); }); server.on("/allblink", HTTP_GET, [](AsyncWebServerRequest *request) { ws.textAll("blinkLamp"); lastSent = "BLINKING"; request->send(200, "text/plain", "Alarming All"); }); server.on("/allnoblink", HTTP_GET, [](AsyncWebServerRequest *request) { ws.textAll("noBlinkLamp"); lastSent = "off"; request->send(200, "text/plain", "Alarm stopped"); }); server.on("/allon", HTTP_GET, [](AsyncWebServerRequest *request) { ws.textAll("lampon"); lastSent = "ON"; request->send(200, "text/plain", "Alarming All"); }); server.on("/alloff", HTTP_GET, [](AsyncWebServerRequest *request) { ws.textAll("lampoff"); lastSent = "off"; request->send(200, "text/plain", "Alarm stopped"); }); server.onNotFound(notFound); server.begin(); MDNS.addService("http", "tcp", 80); } void loop() { if (digitalRead(PIN_ACTIVATE) != inputActive) { delay(10); if (digitalRead(PIN_ACTIVATE) != inputActive) { inputActive = digitalRead(PIN_ACTIVATE); if (!inputActive) { // React when the signal starts if (activateTimeout == 0 || millis() - activateTimeout >= TRIGGER_TIMEOUT) { // 1 Minute timeout Serial.println("Activate triggered"); ws.textAll("lampon"); lastSent = "ON"; } else { Serial.println("Wait 1 minute to retrigger lights"); } } } } if (digitalRead(PIN_CLEAR) != clearActive) { delay(10); if (digitalRead(PIN_CLEAR) != clearActive) { clearActive = digitalRead(PIN_CLEAR); if (clearActive) { // React when the signal is over Serial.println("Clear triggered"); ws.textAll("lampoff"); lastSent = "off"; activateTimeout = millis(); } } } } ///////////////////////////