diff --git a/platformio.ini b/platformio.ini
index 7d72a23c298ddf5fb310c5bbebad12e399908089..b8f71df7a07e842b90e3e9a222fc647f0e6225d9 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -15,6 +15,7 @@ framework = arduino
 upload_port = COM8
 monitor_port = COM8
 monitor_speed = 115200
+monitor_filters = esp32_exception_decoder
 board_build.filesystem = littlefs
 lib_deps = 
     https://github.com/ayushsharma82/ESPConnect.git
@@ -22,6 +23,7 @@ lib_deps =
 	https://github.com/me-no-dev/ESPAsyncWebServer.git
     https://github.com/PlummersSoftwareLLC/SmartMatrix.git
     https://github.com/sstaub/TickTwo.git
+    https://github.com/LennartHennigs/ESPTelnet.git
 
 [env:esp32dev_ota]
 extends = env:esp32dev
diff --git a/src/display.cpp b/src/display.cpp
index 974f632139be920c504091d350b4edd08691f28c..84f59653851a9aedea93a4aedb3def4227016609 100644
--- a/src/display.cpp
+++ b/src/display.cpp
@@ -2,6 +2,7 @@
 #include "gameoflife.h"
 #include "display.h"
 #include "network.h"
+#include "utils.h"
 
 #define COLOR_DEPTH 24                                        // known working: 24, 48 - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24
 const uint8_t kMatrixWidth = 64;                              // known working: 32, 64, 96, 128
@@ -54,12 +55,12 @@ void showEndScreen(int ticks)
 
 void fadeOutGame(int brightness)
 {
-  char msg[38];
+  char msg[64];
   sprintf(msg, "Setting game layer brightness to: %d", brightness);
-  sendEvent("display", msg);
+  logLine(msg);
   brightness = lightPowerMap8bit[brightness];
   backgroundLayer.setBrightness(brightness);
-  // backgroundLayer.swapBuffers(false);
+  //backgroundLayer.swapBuffers(false);
 }
 
 void showEvolutions(int ticks)
@@ -71,12 +72,12 @@ void showEvolutions(int ticks)
   indexedLayer.drawString((matrix.getScreenWidth() / 2) - (strlen(msg) * 4) / 2, (matrix.getScreenHeight() / 2) - 2 - 5, 1, msg);
   indexedLayer.drawString((matrix.getScreenWidth() / 2) - (strlen(evolutions) * 4) / 2, (matrix.getScreenHeight() / 2) + 2, 1, evolutions);
   indexedLayer.swapBuffers();
-  indexedLayer.fillScreen(0);
 }
 
 void clearDisplay()
 {
-  indexedLayer.swapBuffers(false);
+  indexedLayer.fillScreen(0);
+  indexedLayer.swapBuffers();
   backgroundLayer.fillScreen({0, 0, 0});
   backgroundLayer.setBrightness(255);
   backgroundLayer.swapBuffers(false);
diff --git a/src/gameoflife.cpp b/src/gameoflife.cpp
index f90f80a67daafff10d3572bf5dc07caecd09f15d..89846b787d8c50e6a4948efa7c47640721c157ee 100644
--- a/src/gameoflife.cpp
+++ b/src/gameoflife.cpp
@@ -2,6 +2,7 @@
 #include "display.h"
 #include "gameoflife.h"
 #include "network.h"
+#include "utils.h"
 
 // https://github.com/Stavrosfil/game-of-life-esp32
 
@@ -13,6 +14,7 @@ bool gameOver = false;
 
 int currentTick;
 int finalTicks;
+int cellsAliveNow;
 int cellsAliveBefore;
 int noEvolutionTicks;
 
@@ -32,7 +34,7 @@ void setupGameOfLife()
   {
     addGlider(random(SCREEN_HEIGHT), random(SCREEN_WIDTH), g);
   }
-  sendEvent("game", "Game of Life has been initialized");
+  logLine("Game of Life has been initialized");
 }
 
 void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
@@ -48,9 +50,8 @@ void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
 
 void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
 {
+  cellsAliveNow = 0;
   currentTick++;
-  int cellsAliveNow = 0;
-
   for (int i = 0; i < SCREEN_HEIGHT; i++)
   {
     for (int j = 0; j < SCREEN_WIDTH; j++)
@@ -91,41 +92,6 @@ void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
       a[i][j] = arrayCopy[i][j];
     }
   }
-
-  if (currentTick % 2)
-  {
-    cellsAliveBefore = cellsAliveNow;
-    char msg[50];
-    sprintf(msg, "Cells alive now: %d, Cells alive before: %d", cellsAliveNow, cellsAliveBefore);
-    sendEvent("game", msg);
-  }
-
-  if (cellsAliveNow >= cellsAliveBefore - 3 &&
-      cellsAliveNow <= cellsAliveBefore + 3)
-  {
-    noEvolutionTicks++;
-  }
-  else
-  {
-    noEvolutionTicks = 0;
-  }
-
-  if (noEvolutionTicks > noEvolutionTicksLimit)
-  {
-    if (!gameOver)
-    {
-      finalTicks = currentTick - noEvolutionTicksLimit;
-      currentMillis = millis();
-      showEndScreen(finalTicks);
-      gameOver = true;
-      sendEvent("game", "No Evolution detected anymore, ending Game of Life");
-    }
-    else
-    {
-      int brightness = 255 * (1 - ((millis() - currentMillis) / scoreScreenTimeout));
-      fadeOutGame(brightness);
-    }
-  }
 }
 
 void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
@@ -145,17 +111,60 @@ void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
 
 void gameLoop()
 {
-  if (runGame)
+  if (runGame == false)
   {
-    gameOfLife(g);
-    if (gameOver)
+    return;
+  }
+
+  gameOfLife(g);
+
+  if (gameOver)
+  {
+
+    if (millis() - currentMillis > scoreScreenTimeout)
+    {
+      resetGame();
+    }
+
+    if (noEvolutionTicks > noEvolutionTicksLimit)
     {
-      if (millis() - currentMillis > scoreScreenTimeout)
+      if (gameOver)
       {
-        resetGame();
+        int brightness = 255 * (1 - ((millis() - currentMillis) / scoreScreenTimeout));
+        fadeOutGame(brightness);
       }
     }
   }
+  else
+  {
+
+    if (currentTick % 2)
+    {
+      char msg[61];
+      sprintf(msg, "Cells alive now: %4d, before: %4d - No evolution since: %3d", cellsAliveNow, cellsAliveBefore, noEvolutionTicks);
+      logLine(msg);
+      cellsAliveBefore = cellsAliveNow;
+    }
+
+    if (cellsAliveNow >= cellsAliveBefore - 3 &&
+        cellsAliveNow <= cellsAliveBefore + 3)
+    {
+      noEvolutionTicks++;
+    }
+    else
+    {
+      noEvolutionTicks = 0;
+    }
+
+    if (noEvolutionTicks > noEvolutionTicksLimit)
+    {
+      finalTicks = currentTick - noEvolutionTicksLimit;
+      currentMillis = millis();
+      showEndScreen(finalTicks);
+      gameOver = true;
+      logLine("No Evolution detected anymore, ending Game of Life");
+    }
+  }
 }
 
 void resetGame()
diff --git a/src/network.cpp b/src/network.cpp
index 54c8d7203c17bee33369ff51a39b8b2da2e4eaf8..02d57e10c240f39d96b9b00130c9ccb2b75fbe63 100644
--- a/src/network.cpp
+++ b/src/network.cpp
@@ -1,17 +1,22 @@
 #include <Arduino.h>
+#include <ESPTelnet.h>
 #include "config.h"
 #include "utils.h"
 #include "network.h"
 
 MDNSResponder mdns;
 AsyncWebServer server(80);
-AsyncEventSource events("/events");
+ESPTelnet telnet;
+IPAddress ip;
+
+uint16_t telnetPort = 23;
 
 void setupNetwork()
 {
   setupWifi();
   setupMDNS();
   setupOTA();
+  setupTelnet();
   setupWebserver();
 }
 
@@ -20,6 +25,7 @@ void setupWifi()
   ESPConnect.autoConnect(HOSTNAME);
   if (ESPConnect.begin(&server))
   {
+    ip = WiFi.localIP();
     logLine("Connected to WiFi: ", false);
     logLine(WiFi.localIP().toString());
   }
@@ -45,32 +51,53 @@ void setupMDNS()
 void setupOTA()
 {
   ArduinoOTA.onStart([]()
-                     { events.send("Update Start", "ota"); });
+                     {
+                      runGame = false; 
+                      logLine("Update Start"); });
   ArduinoOTA.onEnd([]()
-                   { events.send("Update End", "ota"); });
+                   {
+                    runGame = true; 
+                    logLine("Update End"); });
   ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
                         {
     char p[32];
     sprintf(p, "Progress: %u%%\n", (progress/(total/100)));
-    events.send(p, "ota"); });
+    logLine(p); });
   ArduinoOTA.onError([](ota_error_t error)
                      {
-    if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota");
-    else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota");
-    else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota");
-    else if(error == OTA_RECEIVE_ERROR) events.send("Receive Failed", "ota");
-    else if(error == OTA_END_ERROR) events.send("End Failed", "ota"); });
+    if(error == OTA_AUTH_ERROR) logLine("OTA Auth Failed");
+    else if(error == OTA_BEGIN_ERROR) logLine("OTA Begin Failed");
+    else if(error == OTA_CONNECT_ERROR) logLine("OTA Connect Failed");
+    else if(error == OTA_RECEIVE_ERROR) logLine("OTA Receive Failed");
+    else if(error == OTA_END_ERROR) logLine("OTA End Failed"); 
+    runGame = true; });
   ArduinoOTA.setHostname(HOSTNAME);
   ArduinoOTA.begin();
 }
 
+void setupTelnet()
+{
+  telnet.onConnect(onTelnetConnect);
+  telnet.onConnectionAttempt(onTelnetConnectionAttempt);
+  telnet.onReconnect(onTelnetReconnect);
+  telnet.onDisconnect(onTelnetDisconnect);
+  telnet.onInputReceived(onTelnetInput);
+
+  Serial.print("- Telnet: ");
+  if (telnet.begin(telnetPort))
+  {
+    Serial.println("running");
+  }
+  else
+  {
+    Serial.println("error.");
+  }
+}
+
 void setupWebserver()
 {
   LittleFS.begin();
   server.serveStatic("/", LittleFS, "/");
-  events.onConnect([](AsyncEventSourceClient *client)
-                   { client->send("hello!", NULL, millis(), 1000); });
-  server.addHandler(&events);
   server.onNotFound([](AsyncWebServerRequest *request)
                     { request->send(404); });
   server.begin();
@@ -79,8 +106,56 @@ void setupWebserver()
 void networkLoop()
 {
   ArduinoOTA.handle();
+  if (runGame)
+  {
+    telnet.loop();
+  }
 }
 
-void sendEvent(const char *tag, const char *msg) {
-  events.send(msg, tag);
+// (optional) callback functions for telnet events
+void onTelnetConnect(String ip)
+{
+  Serial.print("- Telnet: ");
+  Serial.print(ip);
+  Serial.println(" connected");
+
+  telnet.println("\nWelcome " + telnet.getIP());
+  telnet.println("Use CTRL+q to disconnect.\n");
+}
+
+void onTelnetDisconnect(String ip)
+{
+  Serial.print("- Telnet: ");
+  Serial.print(ip);
+  Serial.println(" disconnected");
+}
+
+void onTelnetReconnect(String ip)
+{
+  Serial.print("- Telnet: ");
+  Serial.print(ip);
+  Serial.println(" reconnected");
+}
+
+void onTelnetConnectionAttempt(String ip)
+{
+  Serial.print("- Telnet: ");
+  Serial.print(ip);
+  Serial.println(" tried to connected");
+}
+
+void onTelnetInput(String str)
+{
+  // checks for a certain command
+  if (str == "ping")
+  {
+    telnet.println("> pong");
+    Serial.println("- Telnet: pong");
+    // disconnect the client
+  }
+  else if (str == "quit")
+  {
+    telnet.println("> disconnecting you...");
+    telnet.disconnectClient();
+  }
 }
diff --git a/src/network.h b/src/network.h
index e77c7c7bc6cccf4718b22dc248169f5fb3e583c3..ae38bd386f77a11a75c8e2b1afcd61755e9a24c0 100644
--- a/src/network.h
+++ b/src/network.h
@@ -17,8 +17,13 @@ void setupNetwork();
 void setupMDNS();
 void setupWifi();
 void setupOTA();
+void setupTelnet();
 void setupWebserver();
 void networkLoop();
-void sendEvent(const char *tag, const char *msg);
+void onTelnetConnect(String ip);
+void onTelnetDisconnect(String ip);
+void onTelnetReconnect(String ip);
+void onTelnetConnectionAttempt(String ip);
+void onTelnetInput(String str);
 
 #endif
diff --git a/src/utils.cpp b/src/utils.cpp
index 469daaeb28c72444af7f87065805a5a6740fd3b0..ee717d1fdb6dd2df29ec23b37ff685367336a4ff 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -1,11 +1,14 @@
 #include <Arduino.h>
+#include <ESPTelnet.h>
 #include "utils.h"
 
 void logLine(String line, bool newline)
 {
   Serial.print(line);
+  telnet.print(line);
   if (newline)
   {
     Serial.println();
+    telnet.println();
   }
 }
diff --git a/src/utils.h b/src/utils.h
index 185eab8bcbc6295b0cc22081d82867d6cb4254a6..80c497e2e70c6215174c419ef5baea0211c1e36c 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -2,6 +2,10 @@
 #define UTILS_H
 
 #include <Arduino.h>
+#include <ESPTelnet.h>
+
 void logLine(String line, bool newline = true);
 
+extern ESPTelnet telnet;
+
 #endif