//
// Web_Neopixel_C3.ino
//
// Requires three Libraries:
//    U8G2 Graphics Library (https://github.com/olikraus/u8g2/wiki)
//    Adafruit_NeoPixel (https://github.com/adafruit/Adafruit_NeoPixel)
//    ESPAsyncWebSrv (https://github.com/dvarrel/ESPAsyncWebSrv)
// All three can be installed from Arduino IDE Library Manager
//
// This code has been modified for use on the HackerBox LoRa C3 OLED Kit
//    from HackerBox 0111:
//    https://hackerboxes.com/products/hackerbox-0111-relay
//
// Modified from:
// https://github.com/TechTalkies/YouTube/tree/main/44%20NeoPixel%20Webserver
// Originally by Tech Talkies -> video: https://youtu.be/06GzVdYPHHA
//

// Replace with your network credentials (must be 2.4GHz network)
const char* ssid = "WiFi SSID";
const char* password = "Password";

#include <Adafruit_NeoPixel.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebSrv.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "webpage.h"

#define RGBLEDPIN     21
#define OLED_SDA_PIN  5
#define OLED_SCL_PIN  6

U8G2_SSD1306_72X40_ER_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
const char* input_parameter = "value";
bool LEDstates[16];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, RGBLEDPIN, NEO_GRB + NEO_KHZ800);
AsyncWebServer localServer(80);

uint32_t ledColor;
int currentLED = 0;
uint8_t LEDmode = 0;

String processor(const String& var) {
  if (var == "STARTCOLOR") {
    return "#00ff4c";
  }
  return String();
}

void setup() {
  Serial.begin(9600);
  
  Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN);
  u8g2.begin();

  strip.begin();
  strip.setBrightness(100);

  connectWifi();

  localServer.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
    request->send_P(200, "text/html", index_html, processor);
  });

  localServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest* request) {
    String message;
    if (request->hasParam(input_parameter)) {
      message = request->getParam(input_parameter)->value();

      if (message == "all") {
        LEDmode = 3;
      } else if (message == "single") {
        LEDmode = 2;
      } else if (message == "select") {
        LEDmode = 1;
      }
      updateLEDs();
    } else {
      message = "No message sent";
    }
    Serial.println(message);
    request->send(200, "text/plain", "OK");
  });

  localServer.on("/LED", HTTP_GET, [](AsyncWebServerRequest* request) {
    String message;
    if (request->hasParam(input_parameter)) {
      message = request->getParam(input_parameter)->value();
      bool LEDon = !LEDstates[message.toInt()];
      LEDstates[message.toInt()] = LEDon;
      if (LEDon)
        strip.setPixelColor(message.toInt(), ledColor);
      else
        strip.setPixelColor(message.toInt(), 0);
      strip.show();
    } else {
      message = "No message sent";
    }
    Serial.println(message);
    request->send(200, "text/plain", "OK");
  });

  localServer.on("/single", HTTP_GET, [](AsyncWebServerRequest* request) {
    String message;
    if (request->hasParam(input_parameter)) {
      message = request->getParam(input_parameter)->value();
      currentLED = message.toInt();
    } else {
      message = "No message sent";
    }
    Serial.println(message);
    request->send(200, "text/plain", "OK");
  });

  localServer.on("/color", HTTP_GET, [](AsyncWebServerRequest* request) {
    String message;
    if (request->hasParam(input_parameter)) {
      message = request->getParam(input_parameter)->value();
      ledColor = hexToRGB("#" + message);
      updateLEDs();
    } else {
      message = "No message sent";
    }
    Serial.println(message);
    request->send(200, "text/plain", "OK");
  });

  localServer.begin();
}

void updateLEDs() {
  switch (LEDmode) {
    case 1:
    default: setSelectedPixels(); break;
    case 2: strip.setPixelColor(currentLED, ledColor); break;
    case 3: strip.fill(ledColor); break;
  }
  strip.show();
}

void setSelectedPixels() {
  strip.fill(0);
  for (int x = 0; x < 16; x++) {
    if (LEDstates[x])
      strip.setPixelColor(x, ledColor);
  }
  strip.show();
}

void loop() {
  // nothing to see here
}

void connectWifi() {
  uint8_t wifistatus;
  if (WiFi.status() != WL_CONNECTED) { 
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);
    WiFi.setTxPower(WIFI_POWER_8_5dBm);
    wifistatus = WiFi.waitForConnectResult();
    Serial.print("WiFi Connection status:");
    Serial.println(wifistatus);
  }
  if (wifistatus == WL_CONNECTED) {
    IPAddress ipadr = WiFi.localIP();
    char txtout[15];
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(ipadr);
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_6x10_mf);
    u8g2.drawStr(0, 10, "IP Address:");
    sprintf(txtout,"  %i.%i.",ipadr[0],ipadr[1]);
    u8g2.drawStr(0, 27, txtout); 
    sprintf(txtout,"  %i.%i",ipadr[2],ipadr[3]);
    u8g2.drawStr(0, 38, txtout);
    u8g2.sendBuffer();
  } else {
    Serial.println("WiFi connection failed.");
    u8g2.setFont(u8g2_font_6x10_mf);
    u8g2.drawStr(0, 10, " WiFi Failed");
    u8g2.sendBuffer();
    while(true);  //halt
  }
}

uint32_t hexToRGB(String hexstring) {
  // Convert hex string (e.g., "#RRGGBB") to a long integer, removing the "#" at the start
  unsigned long number = strtoul(hexstring.substring(1).c_str(), NULL, 16);

  // Split into R, G, B values
  unsigned long r = (number >> 16) & 0xFF;  // Extract the Red component
  unsigned long g = (number >> 8) & 0xFF;   // Extract the Green component
  unsigned long b = number & 0xFF;          // Extract the Blue component

  // Return the color in RGB format using strip.Color() for NeoPixel
  return strip.Color(r, g, b);
}