Skip to content
Snippets Groups Projects
Select Git revision
  • fd4f9596422c19dd25d17f9eab554039cb152e9c
  • master default protected
2 results

network.cpp

Blame
  • network.cpp 6.21 KiB
    #include <Arduino.h>
    #include <ESPTelnet.h>
    #include "config.h"
    #include "utils.h"
    #include "network.h"
    #include "display.h"
    #include "gameoflife.h"
    
    MDNSResponder mdns;
    AsyncWebServer server(80);
    AsyncWebSocket ws("/ws");
    ESPTelnet telnet;
    IPAddress ip;
    
    int otaProgress = 0;
    
    void setupNetwork()
    {
      setupWifi();
      setupMDNS();
      setupOTA();
      setupTelnet();
      setupWebserver();
    }
    
    void setupWifi()
    {
      ESPConnect.autoConnect(HOSTNAME);
      if (ESPConnect.begin(&server))
      {
        ip = WiFi.localIP();
        logLine("Connected to WiFi: ", false);
        logLine(WiFi.localIP().toString());
      }
      else
      {
        logLine("Failed to connect to WiFi");
      }
    }
    
    void setupMDNS()
    {
      if (mdns.begin(HOSTNAME))
      {
        logLine("MDNS responder started");
        mdns.addService("http", "tcp", 80);
      }
      else
      {
        logLine("MDNS.begin failed");
      }
    }
    
    void setupOTA()
    {
      ArduinoOTA.onStart([]()
                         {
                          runGame = false;
                          ws.enable(false);
                          ws.textAll("OTA Update Started");
                          ws.closeAll();
                          logLine("Update Start");
                          clearDisplay(); });
      ArduinoOTA.onEnd([]()
                       {
                        otaProgress = 0;
                        runGame = true; 
                        logLine("Update End");
                        clearDisplay(); });
      ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
                            {
                              int percent = ceil(progress/(total/100));
                              if (percent > otaProgress) {
                                char msg[10];
                                sprintf(msg, "OTA:%3d%%", percent);
                                showMessage(msg);
                                logLine("OTA: ", false);
                                logLine((String)percent, false);
                                logLine("%");
                                otaProgress = percent;
                              } });
      ArduinoOTA.onError([](ota_error_t error)
                         {
        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");
        clearDisplay();
        otaProgress = 0;
        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())
      {
        Serial.println("running");
      }
      else
      {
        Serial.println("error.");
      }
    }
    
    void setupWebserver()
    {
      LittleFS.begin();
      ws.onEvent(onEvent);
      server.addHandler(&ws);
      server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request)
                { request->send(200, "text/plain", String(ESP.getFreeHeap())); });
      server.onNotFound([](AsyncWebServerRequest *request)
                        { request->send(404); });
      server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
      server.begin();
    }
    
    void networkLoop()
    {
      ArduinoOTA.handle();
      telnet.loop();
    }
    
    void onTelnetConnect(String ip)
    {
      Serial.print("- Telnet: ");
      Serial.print(ip);
      Serial.println(" connected");
    
      telnet.println("\nWelcome " + telnet.getIP());
      telnet.println("Use 'CTRL+Q, ENTER' 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)
    {
      if (str == "ping")
      {
        telnet.println("> pong");
        Serial.println("- Telnet: pong");
      }
      else if (str == "quit" || str == "exit")
      {
        telnet.println("> disconnecting...");
        telnet.disconnectClient();
      }
      else if (str == "reboot" || str == "reset")
      {
        telnet.println("> rebooting...");
        ESP.restart();
      }
    }
    
    DynamicJsonDocument getConfigJson()
    {
      DynamicJsonDocument doc(200);
      JsonObject config = doc.createNestedObject("config");
      config["brightness"] = defaultBrightness;
      config["interval"] = gameInterval;
      return doc;
    }
    
    void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
    {
      if (type == WS_EVT_CONNECT)
      {
        // client connected
        logLine("WS<< connect");
        logLine("WS>> ping");
        client->ping();
        DynamicJsonDocument doc = getConfigJson();
        size_t strsize = measureJson(doc) + 1;
        char json[strsize];
        serializeJson(doc, json, strsize);
        logLine("WS>> ", false);
        logLine(json);
        ws.text(client->id(), json);
      }
      else if (type == WS_EVT_DISCONNECT)
      {
        logLine("WS<< disconnect");
      }
      else if (type == WS_EVT_ERROR)
      {
        // error was received from the other end
        char msg[64];
        snprintf_P(msg, sizeof(msg), PSTR("WS[%u] error(%u): %s"), client->id(), *((uint16_t *)arg), (char *)data);
        logLine(msg);
      }
      else if (type == WS_EVT_PONG)
      {
        // pong message was received (in response to a ping request maybe)
        logLine("WS<< pong");
      }
      else if (type == WS_EVT_DATA)
      {
        // data packet
        data[len] = 0;
        logLine("WS<< ", false);
        logLine((char *)data);
        handleJson(data);
      }
    }
    
    void handleJson(uint8_t *data)
    {
      StaticJsonDocument<200> doc;
      DeserializationError error = deserializeJson(doc, (char *)data);
      if (error)
      {
        logLine("deserializeJson() failed: ", false);
        logLine(error.c_str());
        return;
      }
    
      if (doc.containsKey("config"))
      {
        updateConfig(doc);
      }
    
      if (doc.containsKey("action"))
      {
        if (doc["action"] == "addGlider")
        {
          addGlider();
        }
        else if (doc["action"] == "reboot")
        {
          ESP.restart();
        }
      }
    }
    
    void updateConfig(StaticJsonDocument<200U> doc)
    {
      gameInterval = doc["config"]["interval"];
      defaultBrightness = doc["config"]["brightness"];
      displayBrightness(defaultBrightness);
    }