Added ESP8266HTTPUpdateServer, better than Arduino OTA

--- Arduino/McLighting/McLighting.ino
+++ Arduino/McLighting/McLighting.ino
@@ -1,688 +1,696 @@
-#include "definitions.h"
-
-// ***************************************************************************
-// Load libraries for: WebServer / WiFiManager / WebSockets
-// ***************************************************************************
-#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
-
-// needed for library WiFiManager
-#include <DNSServer.h>
-#include <ESP8266WebServer.h>
-#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
-
-#include <WiFiClient.h>
-#include <ESP8266mDNS.h>
-#include <FS.h>
-#include <EEPROM.h>
-
-#include <WebSockets.h>           //https://github.com/Links2004/arduinoWebSockets
-#include <WebSocketsServer.h>
-
-// OTA
-#ifdef ENABLE_OTA
-  #include <WiFiUdp.h>
-  #include <ArduinoOTA.h>
-#endif
-
-// MQTT
-#ifdef ENABLE_MQTT
-  #include <PubSubClient.h>
-
-  WiFiClient espClient;
-  PubSubClient mqtt_client(espClient);
-#endif
-
-
-// ***************************************************************************
-// Instanciate HTTP(80) / WebSockets(81) Server
-// ***************************************************************************
-ESP8266WebServer server(80);
-WebSocketsServer webSocket = WebSocketsServer(81);
-
-
-// ***************************************************************************
-// Load libraries / Instanciate WS2812FX library
-// ***************************************************************************
-// https://github.com/kitesurfer1404/WS2812FX
-#include <WS2812FX.h>
-WS2812FX strip = WS2812FX(NUMLEDS, PIN, NEO_GRB + NEO_KHZ800);
-
-// Parameter 1 = number of pixels in strip
-// Parameter 2 = Arduino pin number (most are valid)
-// Parameter 3 = pixel type flags, add together as needed:
-//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
-//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
-//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
-//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
-
-// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
-// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
-// and minimize distance between Arduino and first pixel.  Avoid connecting
-// on a live circuit...if you must, connect GND first.
-
-
-// ***************************************************************************
-// Load library "ticker" for blinking status led
-// ***************************************************************************
-#include <Ticker.h>
-Ticker ticker;
-
-void tick()
-{
-  //toggle state
-  int state = digitalRead(BUILTIN_LED);  // get the current state of GPIO1 pin
-  digitalWrite(BUILTIN_LED, !state);     // set pin to the opposite state
-}
-
-
-// ***************************************************************************
-// EEPROM helper
-// ***************************************************************************
-String readEEPROM(int offset, int len) {
-  String res = "";
-  for (int i = 0; i < len; ++i)
-  {
-    res += char(EEPROM.read(i + offset));
-    //DBG_OUTPUT_PORT.println(char(EEPROM.read(i + offset)));
-  }
-  DBG_OUTPUT_PORT.printf("readEEPROM(): %s\n", res.c_str());
-  return res;
-}
-
-void writeEEPROM(int offset, int len, String value) {
-  DBG_OUTPUT_PORT.printf("writeEEPROM(): %s\n", value.c_str());
-  for (int i = 0; i < len; ++i)
-  {
-    if (i < value.length()) {
-      EEPROM.write(i + offset, value[i]);
-    } else {
-      EEPROM.write(i + offset, NULL);
-    }
-  }
-}
-
-
-// ***************************************************************************
-// Saved state handling
-// ***************************************************************************
-// https://stackoverflow.com/questions/9072320/split-string-into-string-array
-String getValue(String data, char separator, int index)
-{
-  int found = 0;
-  int strIndex[] = {0, -1};
-  int maxIndex = data.length()-1;
-
-  for(int i=0; i<=maxIndex && found<=index; i++){
-    if(data.charAt(i)==separator || i==maxIndex){
-        found++;
-        strIndex[0] = strIndex[1]+1;
-        strIndex[1] = (i == maxIndex) ? i+1 : i;
-    }
-  }
-
-  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
-}
-
-
-// ***************************************************************************
-// Callback for WiFiManager library when config mode is entered
-// ***************************************************************************
-//gets called when WiFiManager enters configuration mode
-void configModeCallback (WiFiManager *myWiFiManager) {
-  DBG_OUTPUT_PORT.println("Entered config mode");
-  DBG_OUTPUT_PORT.println(WiFi.softAPIP());
-  //if you used auto generated SSID, print it
-  DBG_OUTPUT_PORT.println(myWiFiManager->getConfigPortalSSID());
-  //entered config mode, make led toggle faster
-  ticker.attach(0.2, tick);
-
-  uint16_t i;
-  for (i = 0; i < strip.numPixels(); i++) {
-    strip.setPixelColor(i, 0, 0, 255);
-  }
-  strip.show();
-}
-
-//callback notifying us of the need to save config
-void saveConfigCallback () {
-  DBG_OUTPUT_PORT.println("Should save config");
-  shouldSaveConfig = true;
-}
-
-// ***************************************************************************
-// Include: Webserver
-// ***************************************************************************
-#include "spiffs_webserver.h"
-
-// ***************************************************************************
-// Include: Request handlers
-// ***************************************************************************
-#include "request_handlers.h"
-
-// ***************************************************************************
-// Include: Color modes
-// ***************************************************************************
-#include "colormodes.h"
-
-
-
-// ***************************************************************************
-// MAIN
-// ***************************************************************************
-void setup() {
-  DBG_OUTPUT_PORT.begin(115200);
-  EEPROM.begin(512);
-
-  // set builtin led pin as output
-  pinMode(BUILTIN_LED, OUTPUT);
-  // button pin setup
-#ifdef ENABLE_BUTTON
-  pinMode(BUTTON,INPUT_PULLUP);
-#endif
-  // start ticker with 0.5 because we start in AP mode and try to connect
-  ticker.attach(0.5, tick);
-
-  wifi_station_set_hostname(const_cast<char*>(HOSTNAME));
-
-  // ***************************************************************************
-  // Setup: Neopixel
-  // ***************************************************************************
-  strip.init();
-  strip.setBrightness(brightness);
-  strip.setSpeed(convertSpeed(ws2812fx_speed));
-  //strip.setMode(FX_MODE_RAINBOW_CYCLE);
-  strip.setColor(main_color.red, main_color.green, main_color.blue);
-  strip.start();
-
-  // ***************************************************************************
-  // Setup: WiFiManager
-  // ***************************************************************************
-  // The extra parameters to be configured (can be either global or just in the setup)
-  // After connecting, parameter.getValue() will get you the configured value
-  // id/name placeholder/prompt default length
-  #ifdef ENABLE_MQTT
-    String settings_available = readEEPROM(134, 1);
-    if (settings_available == "1") {
-      readEEPROM(0, 64).toCharArray(mqtt_host, 64);   // 0-63
-      readEEPROM(64, 6).toCharArray(mqtt_port, 6);    // 64-69
-      readEEPROM(70, 32).toCharArray(mqtt_user, 32);  // 70-101
-      readEEPROM(102, 32).toCharArray(mqtt_pass, 32); // 102-133
-      DBG_OUTPUT_PORT.printf("MQTT host: %s\n", mqtt_host);
-      DBG_OUTPUT_PORT.printf("MQTT port: %s\n", mqtt_port);
-      DBG_OUTPUT_PORT.printf("MQTT user: %s\n", mqtt_user);
-      DBG_OUTPUT_PORT.printf("MQTT pass: %s\n", mqtt_pass);
-    }
-
-    WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64);
-    WiFiManagerParameter custom_mqtt_port("port", "MQTT port", mqtt_port, 6);
-    WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32);
-    WiFiManagerParameter custom_mqtt_pass("pass", "MQTT pass", mqtt_pass, 32);
-  #endif
-
-  //Local intialization. Once its business is done, there is no need to keep it around
-  WiFiManager wifiManager;
-  //reset settings - for testing
-  //wifiManager.resetSettings();
-
-  //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
-  wifiManager.setAPCallback(configModeCallback);
-
-  #ifdef ENABLE_MQTT
-    //set config save notify callback
-    wifiManager.setSaveConfigCallback(saveConfigCallback);
-
-    //add all your parameters here
-    wifiManager.addParameter(&custom_mqtt_host);
-    wifiManager.addParameter(&custom_mqtt_port);
-    wifiManager.addParameter(&custom_mqtt_user);
-    wifiManager.addParameter(&custom_mqtt_pass);
-  #endif
-
-  //fetches ssid and pass and tries to connect
-  //if it does not connect it starts an access point with the specified name
-  //here  "AutoConnectAP"
-  //and goes into a blocking loop awaiting configuration
-  if (!wifiManager.autoConnect(HOSTNAME)) {
-    DBG_OUTPUT_PORT.println("failed to connect and hit timeout");
-    //reset and try again, or maybe put it to deep sleep
-    ESP.reset();
-    delay(1000);
-  }
-
-  #ifdef ENABLE_MQTT
-    //read updated parameters
-    strcpy(mqtt_host, custom_mqtt_host.getValue());
-    strcpy(mqtt_port, custom_mqtt_port.getValue());
-    strcpy(mqtt_user, custom_mqtt_user.getValue());
-    strcpy(mqtt_pass, custom_mqtt_pass.getValue());
-
-    //save the custom parameters to FS
-    if (shouldSaveConfig) {
-      DBG_OUTPUT_PORT.println("Saving WiFiManager config");
-
-      writeEEPROM(0, 64, mqtt_host);   // 0-63
-      writeEEPROM(64, 6, mqtt_port);   // 64-69
-      writeEEPROM(70, 32, mqtt_user);  // 70-101
-      writeEEPROM(102, 32, mqtt_pass); // 102-133
-      writeEEPROM(134, 1, "1");        // 134 --> always "1"
-      EEPROM.commit();
-    }
-  #endif
-
-  //if you get here you have connected to the WiFi
-  DBG_OUTPUT_PORT.println("connected...yeey :)");
-  ticker.detach();
-  //keep LED on
-  digitalWrite(BUILTIN_LED, LOW);
-
-
-  // ***************************************************************************
-  // Configure OTA
-  // ***************************************************************************
-  #ifdef ENABLE_OTA
-    DBG_OUTPUT_PORT.println("Arduino OTA activated.");
-
-    // Port defaults to 8266
-    ArduinoOTA.setPort(8266);
-
-    // Hostname defaults to esp8266-[ChipID]
-    ArduinoOTA.setHostname(HOSTNAME);
-
-    // No authentication by default
-    // ArduinoOTA.setPassword("admin");
-
-    // Password can be set with it's md5 value as well
-    // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
-    // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
-
-    ArduinoOTA.onStart([]() {
-      DBG_OUTPUT_PORT.println("Arduino OTA: Start updating");
-    });
-    ArduinoOTA.onEnd([]() {
-      DBG_OUTPUT_PORT.println("Arduino OTA: End");
-    });
-    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
-      DBG_OUTPUT_PORT.printf("Arduino OTA Progress: %u%%\r", (progress / (total / 100)));
-    });
-    ArduinoOTA.onError([](ota_error_t error) {
-      DBG_OUTPUT_PORT.printf("Arduino OTA Error[%u]: ", error);
-      if (error == OTA_AUTH_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Auth Failed");
-      else if (error == OTA_BEGIN_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Begin Failed");
-      else if (error == OTA_CONNECT_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Connect Failed");
-      else if (error == OTA_RECEIVE_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Receive Failed");
-      else if (error == OTA_END_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: End Failed");
-    });
-
-    ArduinoOTA.begin();
-    DBG_OUTPUT_PORT.println("");
-  #endif
-
-
-  // ***************************************************************************
-  // Configure MQTT
-  // ***************************************************************************
-  #ifdef ENABLE_MQTT
-    if (mqtt_host != "" && String(mqtt_port).toInt() > 0) {
-      snprintf(mqtt_intopic, sizeof mqtt_intopic, "%s/in", HOSTNAME);
-      snprintf(mqtt_outtopic, sizeof mqtt_outtopic, "%s/out", HOSTNAME);
-
-      DBG_OUTPUT_PORT.printf("MQTT active: %s:%d\n", mqtt_host, String(mqtt_port).toInt());
-
-      mqtt_client.setServer(mqtt_host, String(mqtt_port).toInt());
-      mqtt_client.setCallback(mqtt_callback);
-    }
-  #endif
-
-
-  // ***************************************************************************
-  // Setup: MDNS responder
-  // ***************************************************************************
-  bool mdns_result = MDNS.begin(HOSTNAME);
-
-  DBG_OUTPUT_PORT.print("Open http://");
-  DBG_OUTPUT_PORT.print(WiFi.localIP());
-  DBG_OUTPUT_PORT.println("/ to open McLighting.");
-
-  DBG_OUTPUT_PORT.print("Use http://");
-  DBG_OUTPUT_PORT.print(HOSTNAME);
-  DBG_OUTPUT_PORT.println(".local/ when you have Bonjour installed.");
-
-  DBG_OUTPUT_PORT.print("New users: Open http://");
-  DBG_OUTPUT_PORT.print(WiFi.localIP());
-  DBG_OUTPUT_PORT.println("/upload to upload the webpages first.");
-
-  DBG_OUTPUT_PORT.println("");
-
-
-  // ***************************************************************************
-  // Setup: WebSocket server
-  // ***************************************************************************
-  webSocket.begin();
-  webSocket.onEvent(webSocketEvent);
-
-
-  // ***************************************************************************
-  // Setup: SPIFFS
-  // ***************************************************************************
-  SPIFFS.begin();
-  {
-    Dir dir = SPIFFS.openDir("/");
-    while (dir.next()) {
-      String fileName = dir.fileName();
-      size_t fileSize = dir.fileSize();
-      DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
-    }
-
-    FSInfo fs_info;
-    SPIFFS.info(fs_info);
-    DBG_OUTPUT_PORT.printf("FS Usage: %d/%d bytes\n\n", fs_info.usedBytes, fs_info.totalBytes);
-  }
-
-  // ***************************************************************************
-  // Setup: SPIFFS Webserver handler
-  // ***************************************************************************
-  //list directory
-  server.on("/list", HTTP_GET, handleFileList);
-  //load editor
-  server.on("/edit", HTTP_GET, []() {
-    if (!handleFileRead("/edit.htm")) server.send(404, "text/plain", "FileNotFound");
-  });
-  //create file
-  server.on("/edit", HTTP_PUT, handleFileCreate);
-  //delete file
-  server.on("/edit", HTTP_DELETE, handleFileDelete);
-  //first callback is called after the request has ended with all parsed arguments
-  //second callback handles file uploads at that location
-  server.on("/edit", HTTP_POST, []() {
-    server.send(200, "text/plain", "");
-  }, handleFileUpload);
-  //get heap status, analog input value and all GPIO statuses in one json call
-  server.on("/esp_status", HTTP_GET, []() {
-    String json = "{";
-    json += "\"heap\":" + String(ESP.getFreeHeap());
-    // json += ", \"analog\":" + String(analogRead(A0));
-    // json += ", \"gpio\":" + String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16)));
-    json += "}";
-    server.send(200, "text/json", json);
-    json = String();
-  });
-
-
-  //called when the url is not defined here
-  //use it to load content from SPIFFS
-  server.onNotFound([]() {
-    if (!handleFileRead(server.uri()))
-      handleNotFound();
-  });
-
-  server.on("/upload", handleMinimalUpload);
-
-  server.on("/restart", []() {
-    DBG_OUTPUT_PORT.printf("/restart\n");
-    server.send(200, "text/plain", "restarting..." );
-    ESP.restart();
-  });
-
-  server.on("/reset_wlan", []() {
-    DBG_OUTPUT_PORT.printf("/reset_wlan\n");
-    server.send(200, "text/plain", "Resetting WLAN and restarting..." );
-    WiFiManager wifiManager;
-    wifiManager.resetSettings();
-    ESP.restart();
-  });
-
-  server.on("/start_config_ap", []() {
-    DBG_OUTPUT_PORT.printf("/start_config_ap\n");
-    server.send(200, "text/plain", "Starting config AP ..." );
-    WiFiManager wifiManager;
-    wifiManager.startConfigPortal(HOSTNAME);
-  });
-
-
-  // ***************************************************************************
-  // Setup: SPIFFS Webserver handler
-  // ***************************************************************************
-  server.on("/set_brightness", []() {
-    if (server.arg("c").toInt() > 0) {
-      brightness = (int) server.arg("c").toInt() * 2.55;
-    } else {
-      brightness = server.arg("p").toInt();
-    }
-    if (brightness > 255) {
-      brightness = 255;
-    }
-    if (brightness < 0) {
-      brightness = 0;
-    }
-    strip.setBrightness(brightness);
-
-    if (mode == HOLD) {
-      mode = ALL;
-    }
-
-    getStatusJSON();
-  });
-
-  server.on("/get_brightness", []() {
-    String str_brightness = String((int) (brightness / 2.55));
-    server.send(200, "text/plain", str_brightness );
-    DBG_OUTPUT_PORT.print("/get_brightness: ");
-    DBG_OUTPUT_PORT.println(str_brightness);
-  });
-
-  server.on("/set_speed", []() {
-    if (server.arg("d").toInt() >= 0) {
-      ws2812fx_speed = server.arg("d").toInt();
-      ws2812fx_speed = constrain(ws2812fx_speed, 0, 255);
-      strip.setSpeed(convertSpeed(ws2812fx_speed));
-    }
-
-    getStatusJSON();
-  });
-
-  server.on("/get_speed", []() {
-    String str_speed = String(ws2812fx_speed);
-    server.send(200, "text/plain", str_speed );
-    DBG_OUTPUT_PORT.print("/get_speed: ");
-    DBG_OUTPUT_PORT.println(str_speed);
-  });
-
-  server.on("/get_switch", []() {
-    server.send(200, "text/plain", (mode == OFF) ? "0" : "1" );
-    DBG_OUTPUT_PORT.printf("/get_switch: %s\n", (mode == OFF) ? "0" : "1");
-  });
-
-  server.on("/get_color", []() {
-    String rgbcolor = String(main_color.red, HEX) + String(main_color.green, HEX) + String(main_color.blue, HEX);
-    server.send(200, "text/plain", rgbcolor );
-    DBG_OUTPUT_PORT.print("/get_color: ");
-    DBG_OUTPUT_PORT.println(rgbcolor);
-  });
-
-  server.on("/status", []() {
-    getStatusJSON();
-  });
-
-  server.on("/off", []() {
-    exit_func = true;
-    mode = OFF;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/all", []() {
-    exit_func = true;
-    mode = ALL;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/wipe", []() {
-    exit_func = true;
-    mode = WIPE;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/rainbow", []() {
-    exit_func = true;
-    mode = RAINBOW;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/rainbowCycle", []() {
-    exit_func = true;
-    mode = RAINBOWCYCLE;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/theaterchase", []() {
-    exit_func = true;
-    mode = THEATERCHASE;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/theaterchaseRainbow", []() {
-    exit_func = true;
-    mode = THEATERCHASERAINBOW;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/tv", []() {
-    exit_func = true;
-    mode = TV;
-    getArgs();
-    getStatusJSON();
-  });
-
-  server.on("/get_modes", []() {
-    getModesJSON();
-  });
-
-  server.on("/set_mode", []() {
-    getArgs();
-    mode = SET_MODE;
-    getStatusJSON();
-  });
-
-  server.begin();
-
-  // Start MDNS service
-  if (mdns_result) {
-    MDNS.addService("http", "tcp", 80);
-  }
-
-  #ifdef ENABLE_STATE_SAVE
-    // Load state string from EEPROM
-    String saved_state_string = readEEPROM(256, 32);
-    String chk = getValue(saved_state_string, '|', 0);
-    if (chk == "STA") {
-      DBG_OUTPUT_PORT.printf("Found saved state: %s\n", saved_state_string.c_str());
-      setModeByStateString(saved_state_string);
-    }
-    sprintf(last_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, ws2812fx_mode, ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue);
-  #endif
-}
-
-
-void loop() {
-  #ifdef ENABLE_BUTTON
-    button();
-  #endif
-  server.handleClient();
-  webSocket.loop();
-
-  #ifdef ENABLE_OTA
-    ArduinoOTA.handle();
-  #endif
-
-  #ifdef ENABLE_MQTT
-    if (mqtt_host != "" && String(mqtt_port).toInt() > 0 && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) {
-      if (!mqtt_client.connected()) {
-        mqtt_reconnect();
-      } else {
-        mqtt_client.loop();
-      }
-    }
-  #endif
-
-  // Simple statemachine that handles the different modes
-  if (mode == SET_MODE) {
-    DBG_OUTPUT_PORT.printf("SET_MODE: %d %d\n", ws2812fx_mode, mode);
-    strip.setMode(ws2812fx_mode);
-    mode = HOLD;
-  }
-  if (mode == OFF) {
-    strip.setColor(0,0,0);
-    strip.setMode(FX_MODE_STATIC);
-    // mode = HOLD;
-  }
-  if (mode == ALL) {
-    strip.setColor(main_color.red, main_color.green, main_color.blue);
-    strip.setMode(FX_MODE_STATIC);
-    mode = HOLD;
-  }
-  if (mode == WIPE) {
-    strip.setColor(main_color.red, main_color.green, main_color.blue);
-    strip.setMode(FX_MODE_COLOR_WIPE);
-    mode = HOLD;
-  }
-  if (mode == RAINBOW) {
-    strip.setMode(FX_MODE_RAINBOW);
-    mode = HOLD;
-  }
-  if (mode == RAINBOWCYCLE) {
-    strip.setMode(FX_MODE_RAINBOW_CYCLE);
-    mode = HOLD;
-  }
-  if (mode == THEATERCHASE) {
-    strip.setColor(main_color.red, main_color.green, main_color.blue);
-    strip.setMode(FX_MODE_THEATER_CHASE);
-    mode = HOLD;
-  }
-  if (mode == TWINKLERANDOM) {
-    strip.setColor(main_color.red, main_color.green, main_color.blue);
-    strip.setMode(FX_MODE_TWINKLE_RANDOM);
-    mode = HOLD;
-  }
-  if (mode == THEATERCHASERAINBOW) {
-    strip.setMode(FX_MODE_THEATER_CHASE_RAINBOW);
-    mode = HOLD;
-  }
-  if (mode == HOLD || mode == CUSTOM) {
-    if (exit_func) {
-      exit_func = false;
-    }
-  }
-  if (mode == TV) {
-    tv();
-  }
-
-  // Only for modes with WS2812FX functionality
-  if (mode != TV && mode != CUSTOM) {
-    strip.service();
-  }
-
-
-  #ifdef ENABLE_STATE_SAVE
-    // Check for state changes
-    sprintf(current_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, strip.getMode(), ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue);
-
-    if (strcmp(current_state, last_state) != 0) {
-      // DBG_OUTPUT_PORT.printf("STATE CHANGED: %s / %s\n", last_state, current_state);
-      strcpy(last_state, current_state);
-      time_statechange = millis();
-      state_save_requested = true;
-    }
-    if (state_save_requested && time_statechange + timeout_statechange_save <= millis()) {
-      time_statechange = 0;
-      state_save_requested = false;
-      writeEEPROM(256, 32, last_state); // 256 --> last_state (reserved 32 bytes)
-      EEPROM.commit();
-    }
-  #endif
-}
+#include "definitions.h"
+
+// ***************************************************************************
+// Load libraries for: WebServer / WiFiManager / WebSockets
+// ***************************************************************************
+#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
+
+// needed for library WiFiManager
+#include <DNSServer.h>
+#include <ESP8266WebServer.h>
+#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
+
+#include <WiFiClient.h>
+#include <ESP8266mDNS.h>
+#include <FS.h>
+#include <EEPROM.h>
+
+#include <WebSockets.h>           //https://github.com/Links2004/arduinoWebSockets
+#include <WebSocketsServer.h>
+
+// OTA
+#ifdef ENABLE_OTA
+  #include <WiFiUdp.h>
+  #include <ArduinoOTA.h>
+#endif
+
+// MQTT
+#ifdef ENABLE_MQTT
+  #include <PubSubClient.h>
+
+  WiFiClient espClient;
+  PubSubClient mqtt_client(espClient);
+#endif
+
+
+// ***************************************************************************
+// Instanciate HTTP(80) / WebSockets(81) Server
+// ***************************************************************************
+ESP8266WebServer server(80);
+WebSocketsServer webSocket = WebSocketsServer(81);
+
+#ifdef HTTP_OTA
+  #include <ESP8266HTTPUpdateServer.h>
+  ESP8266HTTPUpdateServer httpUpdater;
+#endif
+
+// ***************************************************************************
+// Load libraries / Instanciate WS2812FX library
+// ***************************************************************************
+// https://github.com/kitesurfer1404/WS2812FX
+#include <WS2812FX.h>
+WS2812FX strip = WS2812FX(NUMLEDS, PIN, NEO_GRB + NEO_KHZ800);
+
+// Parameter 1 = number of pixels in strip
+// Parameter 2 = Arduino pin number (most are valid)
+// Parameter 3 = pixel type flags, add together as needed:
+//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
+//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
+//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
+//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
+
+// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
+// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
+// and minimize distance between Arduino and first pixel.  Avoid connecting
+// on a live circuit...if you must, connect GND first.
+
+
+// ***************************************************************************
+// Load library "ticker" for blinking status led
+// ***************************************************************************
+#include <Ticker.h>
+Ticker ticker;
+
+void tick()
+{
+  //toggle state
+  int state = digitalRead(BUILTIN_LED);  // get the current state of GPIO1 pin
+  digitalWrite(BUILTIN_LED, !state);     // set pin to the opposite state
+}
+
+
+// ***************************************************************************
+// EEPROM helper
+// ***************************************************************************
+String readEEPROM(int offset, int len) {
+  String res = "";
+  for (int i = 0; i < len; ++i)
+  {
+    res += char(EEPROM.read(i + offset));
+    //DBG_OUTPUT_PORT.println(char(EEPROM.read(i + offset)));
+  }
+  DBG_OUTPUT_PORT.printf("readEEPROM(): %s\n", res.c_str());
+  return res;
+}
+
+void writeEEPROM(int offset, int len, String value) {
+  DBG_OUTPUT_PORT.printf("writeEEPROM(): %s\n", value.c_str());
+  for (int i = 0; i < len; ++i)
+  {
+    if (i < value.length()) {
+      EEPROM.write(i + offset, value[i]);
+    } else {
+      EEPROM.write(i + offset, NULL);
+    }
+  }
+}
+
+
+// ***************************************************************************
+// Saved state handling
+// ***************************************************************************
+// https://stackoverflow.com/questions/9072320/split-string-into-string-array
+String getValue(String data, char separator, int index)
+{
+  int found = 0;
+  int strIndex[] = {0, -1};
+  int maxIndex = data.length()-1;
+
+  for(int i=0; i<=maxIndex && found<=index; i++){
+    if(data.charAt(i)==separator || i==maxIndex){
+        found++;
+        strIndex[0] = strIndex[1]+1;
+        strIndex[1] = (i == maxIndex) ? i+1 : i;
+    }
+  }
+
+  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
+}
+
+
+// ***************************************************************************
+// Callback for WiFiManager library when config mode is entered
+// ***************************************************************************
+//gets called when WiFiManager enters configuration mode
+void configModeCallback (WiFiManager *myWiFiManager) {
+  DBG_OUTPUT_PORT.println("Entered config mode");
+  DBG_OUTPUT_PORT.println(WiFi.softAPIP());
+  //if you used auto generated SSID, print it
+  DBG_OUTPUT_PORT.println(myWiFiManager->getConfigPortalSSID());
+  //entered config mode, make led toggle faster
+  ticker.attach(0.2, tick);
+
+  uint16_t i;
+  for (i = 0; i < strip.numPixels(); i++) {
+    strip.setPixelColor(i, 0, 0, 255);
+  }
+  strip.show();
+}
+
+//callback notifying us of the need to save config
+void saveConfigCallback () {
+  DBG_OUTPUT_PORT.println("Should save config");
+  shouldSaveConfig = true;
+}
+
+// ***************************************************************************
+// Include: Webserver
+// ***************************************************************************
+#include "spiffs_webserver.h"
+
+// ***************************************************************************
+// Include: Request handlers
+// ***************************************************************************
+#include "request_handlers.h"
+
+// ***************************************************************************
+// Include: Color modes
+// ***************************************************************************
+#include "colormodes.h"
+
+
+
+// ***************************************************************************
+// MAIN
+// ***************************************************************************
+void setup() {
+  DBG_OUTPUT_PORT.begin(115200);
+  EEPROM.begin(512);
+
+  // set builtin led pin as output
+  pinMode(BUILTIN_LED, OUTPUT);
+  // button pin setup
+#ifdef ENABLE_BUTTON
+  pinMode(BUTTON,INPUT_PULLUP);
+#endif
+  // start ticker with 0.5 because we start in AP mode and try to connect
+  ticker.attach(0.5, tick);
+
+  wifi_station_set_hostname(const_cast<char*>(HOSTNAME));
+
+  // ***************************************************************************
+  // Setup: Neopixel
+  // ***************************************************************************
+  strip.init();
+  strip.setBrightness(brightness);
+  strip.setSpeed(convertSpeed(ws2812fx_speed));
+  //strip.setMode(FX_MODE_RAINBOW_CYCLE);
+  strip.setColor(main_color.red, main_color.green, main_color.blue);
+  strip.start();
+
+  // ***************************************************************************
+  // Setup: WiFiManager
+  // ***************************************************************************
+  // The extra parameters to be configured (can be either global or just in the setup)
+  // After connecting, parameter.getValue() will get you the configured value
+  // id/name placeholder/prompt default length
+  #ifdef ENABLE_MQTT
+    String settings_available = readEEPROM(134, 1);
+    if (settings_available == "1") {
+      readEEPROM(0, 64).toCharArray(mqtt_host, 64);   // 0-63
+      readEEPROM(64, 6).toCharArray(mqtt_port, 6);    // 64-69
+      readEEPROM(70, 32).toCharArray(mqtt_user, 32);  // 70-101
+      readEEPROM(102, 32).toCharArray(mqtt_pass, 32); // 102-133
+      DBG_OUTPUT_PORT.printf("MQTT host: %s\n", mqtt_host);
+      DBG_OUTPUT_PORT.printf("MQTT port: %s\n", mqtt_port);
+      DBG_OUTPUT_PORT.printf("MQTT user: %s\n", mqtt_user);
+      DBG_OUTPUT_PORT.printf("MQTT pass: %s\n", mqtt_pass);
+    }
+
+    WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64);
+    WiFiManagerParameter custom_mqtt_port("port", "MQTT port", mqtt_port, 6);
+    WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32);
+    WiFiManagerParameter custom_mqtt_pass("pass", "MQTT pass", mqtt_pass, 32);
+  #endif
+
+  //Local intialization. Once its business is done, there is no need to keep it around
+  WiFiManager wifiManager;
+  //reset settings - for testing
+  //wifiManager.resetSettings();
+
+  //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
+  wifiManager.setAPCallback(configModeCallback);
+
+  #ifdef ENABLE_MQTT
+    //set config save notify callback
+    wifiManager.setSaveConfigCallback(saveConfigCallback);
+
+    //add all your parameters here
+    wifiManager.addParameter(&custom_mqtt_host);
+    wifiManager.addParameter(&custom_mqtt_port);
+    wifiManager.addParameter(&custom_mqtt_user);
+    wifiManager.addParameter(&custom_mqtt_pass);
+  #endif
+
+  //fetches ssid and pass and tries to connect
+  //if it does not connect it starts an access point with the specified name
+  //here  "AutoConnectAP"
+  //and goes into a blocking loop awaiting configuration
+  if (!wifiManager.autoConnect(HOSTNAME)) {
+    DBG_OUTPUT_PORT.println("failed to connect and hit timeout");
+    //reset and try again, or maybe put it to deep sleep
+    ESP.reset();
+    delay(1000);
+  }
+
+  #ifdef ENABLE_MQTT
+    //read updated parameters
+    strcpy(mqtt_host, custom_mqtt_host.getValue());
+    strcpy(mqtt_port, custom_mqtt_port.getValue());
+    strcpy(mqtt_user, custom_mqtt_user.getValue());
+    strcpy(mqtt_pass, custom_mqtt_pass.getValue());
+
+    //save the custom parameters to FS
+    if (shouldSaveConfig) {
+      DBG_OUTPUT_PORT.println("Saving WiFiManager config");
+
+      writeEEPROM(0, 64, mqtt_host);   // 0-63
+      writeEEPROM(64, 6, mqtt_port);   // 64-69
+      writeEEPROM(70, 32, mqtt_user);  // 70-101
+      writeEEPROM(102, 32, mqtt_pass); // 102-133
+      writeEEPROM(134, 1, "1");        // 134 --> always "1"
+      EEPROM.commit();
+    }
+  #endif
+
+  //if you get here you have connected to the WiFi
+  DBG_OUTPUT_PORT.println("connected...yeey :)");
+  ticker.detach();
+  //keep LED on
+  digitalWrite(BUILTIN_LED, LOW);
+
+
+  // ***************************************************************************
+  // Configure OTA
+  // ***************************************************************************
+  #ifdef ENABLE_OTA
+    DBG_OUTPUT_PORT.println("Arduino OTA activated.");
+
+    // Port defaults to 8266
+    ArduinoOTA.setPort(8266);
+
+    // Hostname defaults to esp8266-[ChipID]
+    ArduinoOTA.setHostname(HOSTNAME);
+
+    // No authentication by default
+    // ArduinoOTA.setPassword("admin");
+
+    // Password can be set with it's md5 value as well
+    // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
+    // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
+
+    ArduinoOTA.onStart([]() {
+      DBG_OUTPUT_PORT.println("Arduino OTA: Start updating");
+    });
+    ArduinoOTA.onEnd([]() {
+      DBG_OUTPUT_PORT.println("Arduino OTA: End");
+    });
+    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+      DBG_OUTPUT_PORT.printf("Arduino OTA Progress: %u%%\r", (progress / (total / 100)));
+    });
+    ArduinoOTA.onError([](ota_error_t error) {
+      DBG_OUTPUT_PORT.printf("Arduino OTA Error[%u]: ", error);
+      if (error == OTA_AUTH_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Auth Failed");
+      else if (error == OTA_BEGIN_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Begin Failed");
+      else if (error == OTA_CONNECT_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Connect Failed");
+      else if (error == OTA_RECEIVE_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: Receive Failed");
+      else if (error == OTA_END_ERROR) DBG_OUTPUT_PORT.println("Arduino OTA: End Failed");
+    });
+
+    ArduinoOTA.begin();
+    DBG_OUTPUT_PORT.println("");
+  #endif
+
+
+  // ***************************************************************************
+  // Configure MQTT
+  // ***************************************************************************
+  #ifdef ENABLE_MQTT
+    if (mqtt_host != "" && String(mqtt_port).toInt() > 0) {
+      snprintf(mqtt_intopic, sizeof mqtt_intopic, "%s/in", HOSTNAME);
+      snprintf(mqtt_outtopic, sizeof mqtt_outtopic, "%s/out", HOSTNAME);
+
+      DBG_OUTPUT_PORT.printf("MQTT active: %s:%d\n", mqtt_host, String(mqtt_port).toInt());
+
+      mqtt_client.setServer(mqtt_host, String(mqtt_port).toInt());
+      mqtt_client.setCallback(mqtt_callback);
+    }
+  #endif
+
+
+  // ***************************************************************************
+  // Setup: MDNS responder
+  // ***************************************************************************
+  bool mdns_result = MDNS.begin(HOSTNAME);
+
+  DBG_OUTPUT_PORT.print("Open http://");
+  DBG_OUTPUT_PORT.print(WiFi.localIP());
+  DBG_OUTPUT_PORT.println("/ to open McLighting.");
+
+  DBG_OUTPUT_PORT.print("Use http://");
+  DBG_OUTPUT_PORT.print(HOSTNAME);
+  DBG_OUTPUT_PORT.println(".local/ when you have Bonjour installed.");
+
+  DBG_OUTPUT_PORT.print("New users: Open http://");
+  DBG_OUTPUT_PORT.print(WiFi.localIP());
+  DBG_OUTPUT_PORT.println("/upload to upload the webpages first.");
+
+  DBG_OUTPUT_PORT.println("");
+
+
+  // ***************************************************************************
+  // Setup: WebSocket server
+  // ***************************************************************************
+  webSocket.begin();
+  webSocket.onEvent(webSocketEvent);
+
+
+  // ***************************************************************************
+  // Setup: SPIFFS
+  // ***************************************************************************
+  SPIFFS.begin();
+  {
+    Dir dir = SPIFFS.openDir("/");
+    while (dir.next()) {
+      String fileName = dir.fileName();
+      size_t fileSize = dir.fileSize();
+      DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
+    }
+
+    FSInfo fs_info;
+    SPIFFS.info(fs_info);
+    DBG_OUTPUT_PORT.printf("FS Usage: %d/%d bytes\n\n", fs_info.usedBytes, fs_info.totalBytes);
+  }
+
+  // ***************************************************************************
+  // Setup: SPIFFS Webserver handler
+  // ***************************************************************************
+  //list directory
+  server.on("/list", HTTP_GET, handleFileList);
+  //load editor
+  server.on("/edit", HTTP_GET, []() {
+    if (!handleFileRead("/edit.htm")) server.send(404, "text/plain", "FileNotFound");
+  });
+  //create file
+  server.on("/edit", HTTP_PUT, handleFileCreate);
+  //delete file
+  server.on("/edit", HTTP_DELETE, handleFileDelete);
+  //first callback is called after the request has ended with all parsed arguments
+  //second callback handles file uploads at that location
+  server.on("/edit", HTTP_POST, []() {
+    server.send(200, "text/plain", "");
+  }, handleFileUpload);
+  //get heap status, analog input value and all GPIO statuses in one json call
+  server.on("/esp_status", HTTP_GET, []() {
+    String json = "{";
+    json += "\"heap\":" + String(ESP.getFreeHeap());
+    // json += ", \"analog\":" + String(analogRead(A0));
+    // json += ", \"gpio\":" + String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16)));
+    json += "}";
+    server.send(200, "text/json", json);
+    json = String();
+  });
+
+
+  //called when the url is not defined here
+  //use it to load content from SPIFFS
+  server.onNotFound([]() {
+    if (!handleFileRead(server.uri()))
+      handleNotFound();
+  });
+
+  server.on("/upload", handleMinimalUpload);
+
+  server.on("/restart", []() {
+    DBG_OUTPUT_PORT.printf("/restart\n");
+    server.send(200, "text/plain", "restarting..." );
+    ESP.restart();
+  });
+
+  server.on("/reset_wlan", []() {
+    DBG_OUTPUT_PORT.printf("/reset_wlan\n");
+    server.send(200, "text/plain", "Resetting WLAN and restarting..." );
+    WiFiManager wifiManager;
+    wifiManager.resetSettings();
+    ESP.restart();
+  });
+
+  server.on("/start_config_ap", []() {
+    DBG_OUTPUT_PORT.printf("/start_config_ap\n");
+    server.send(200, "text/plain", "Starting config AP ..." );
+    WiFiManager wifiManager;
+    wifiManager.startConfigPortal(HOSTNAME);
+  });
+
+
+  // ***************************************************************************
+  // Setup: SPIFFS Webserver handler
+  // ***************************************************************************
+  server.on("/set_brightness", []() {
+    if (server.arg("c").toInt() > 0) {
+      brightness = (int) server.arg("c").toInt() * 2.55;
+    } else {
+      brightness = server.arg("p").toInt();
+    }
+    if (brightness > 255) {
+      brightness = 255;
+    }
+    if (brightness < 0) {
+      brightness = 0;
+    }
+    strip.setBrightness(brightness);
+
+    if (mode == HOLD) {
+      mode = ALL;
+    }
+
+    getStatusJSON();
+  });
+
+  server.on("/get_brightness", []() {
+    String str_brightness = String((int) (brightness / 2.55));
+    server.send(200, "text/plain", str_brightness );
+    DBG_OUTPUT_PORT.print("/get_brightness: ");
+    DBG_OUTPUT_PORT.println(str_brightness);
+  });
+
+  server.on("/set_speed", []() {
+    if (server.arg("d").toInt() >= 0) {
+      ws2812fx_speed = server.arg("d").toInt();
+      ws2812fx_speed = constrain(ws2812fx_speed, 0, 255);
+      strip.setSpeed(convertSpeed(ws2812fx_speed));
+    }
+
+    getStatusJSON();
+  });
+
+  server.on("/get_speed", []() {
+    String str_speed = String(ws2812fx_speed);
+    server.send(200, "text/plain", str_speed );
+    DBG_OUTPUT_PORT.print("/get_speed: ");
+    DBG_OUTPUT_PORT.println(str_speed);
+  });
+
+  server.on("/get_switch", []() {
+    server.send(200, "text/plain", (mode == OFF) ? "0" : "1" );
+    DBG_OUTPUT_PORT.printf("/get_switch: %s\n", (mode == OFF) ? "0" : "1");
+  });
+
+  server.on("/get_color", []() {
+    String rgbcolor = String(main_color.red, HEX) + String(main_color.green, HEX) + String(main_color.blue, HEX);
+    server.send(200, "text/plain", rgbcolor );
+    DBG_OUTPUT_PORT.print("/get_color: ");
+    DBG_OUTPUT_PORT.println(rgbcolor);
+  });
+
+  server.on("/status", []() {
+    getStatusJSON();
+  });
+
+  server.on("/off", []() {
+    exit_func = true;
+    mode = OFF;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/all", []() {
+    exit_func = true;
+    mode = ALL;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/wipe", []() {
+    exit_func = true;
+    mode = WIPE;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/rainbow", []() {
+    exit_func = true;
+    mode = RAINBOW;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/rainbowCycle", []() {
+    exit_func = true;
+    mode = RAINBOWCYCLE;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/theaterchase", []() {
+    exit_func = true;
+    mode = THEATERCHASE;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/theaterchaseRainbow", []() {
+    exit_func = true;
+    mode = THEATERCHASERAINBOW;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/tv", []() {
+    exit_func = true;
+    mode = TV;
+    getArgs();
+    getStatusJSON();
+  });
+
+  server.on("/get_modes", []() {
+    getModesJSON();
+  });
+
+  server.on("/set_mode", []() {
+    getArgs();
+    mode = SET_MODE;
+    getStatusJSON();
+  });
+
+  #ifdef HTTP_OTA
+    httpUpdater.setup(&server,"/update");
+  #endif
+
+  server.begin();
+
+  // Start MDNS service
+  if (mdns_result) {
+    MDNS.addService("http", "tcp", 80);
+  }
+
+  #ifdef ENABLE_STATE_SAVE
+    // Load state string from EEPROM
+    String saved_state_string = readEEPROM(256, 32);
+    String chk = getValue(saved_state_string, '|', 0);
+    if (chk == "STA") {
+      DBG_OUTPUT_PORT.printf("Found saved state: %s\n", saved_state_string.c_str());
+      setModeByStateString(saved_state_string);
+    }
+    sprintf(last_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, ws2812fx_mode, ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue);
+  #endif
+}
+
+
+void loop() {
+  #ifdef ENABLE_BUTTON
+    button();
+  #endif
+  server.handleClient();
+  webSocket.loop();
+
+  #ifdef ENABLE_OTA
+    ArduinoOTA.handle();
+  #endif
+
+  #ifdef ENABLE_MQTT
+    if (mqtt_host != "" && String(mqtt_port).toInt() > 0 && mqtt_reconnect_retries < MQTT_MAX_RECONNECT_TRIES) {
+      if (!mqtt_client.connected()) {
+        mqtt_reconnect();
+      } else {
+        mqtt_client.loop();
+      }
+    }
+  #endif
+
+  // Simple statemachine that handles the different modes
+  if (mode == SET_MODE) {
+    DBG_OUTPUT_PORT.printf("SET_MODE: %d %d\n", ws2812fx_mode, mode);
+    strip.setMode(ws2812fx_mode);
+    mode = HOLD;
+  }
+  if (mode == OFF) {
+    strip.setColor(0,0,0);
+    strip.setMode(FX_MODE_STATIC);
+    // mode = HOLD;
+  }
+  if (mode == ALL) {
+    strip.setColor(main_color.red, main_color.green, main_color.blue);
+    strip.setMode(FX_MODE_STATIC);
+    mode = HOLD;
+  }
+  if (mode == WIPE) {
+    strip.setColor(main_color.red, main_color.green, main_color.blue);
+    strip.setMode(FX_MODE_COLOR_WIPE);
+    mode = HOLD;
+  }
+  if (mode == RAINBOW) {
+    strip.setMode(FX_MODE_RAINBOW);
+    mode = HOLD;
+  }
+  if (mode == RAINBOWCYCLE) {
+    strip.setMode(FX_MODE_RAINBOW_CYCLE);
+    mode = HOLD;
+  }
+  if (mode == THEATERCHASE) {
+    strip.setColor(main_color.red, main_color.green, main_color.blue);
+    strip.setMode(FX_MODE_THEATER_CHASE);
+    mode = HOLD;
+  }
+  if (mode == TWINKLERANDOM) {
+    strip.setColor(main_color.red, main_color.green, main_color.blue);
+    strip.setMode(FX_MODE_TWINKLE_RANDOM);
+    mode = HOLD;
+  }
+  if (mode == THEATERCHASERAINBOW) {
+    strip.setMode(FX_MODE_THEATER_CHASE_RAINBOW);
+    mode = HOLD;
+  }
+  if (mode == HOLD || mode == CUSTOM) {
+    if (exit_func) {
+      exit_func = false;
+    }
+  }
+  if (mode == TV) {
+    tv();
+  }
+
+  // Only for modes with WS2812FX functionality
+  if (mode != TV && mode != CUSTOM) {
+    strip.service();
+  }
+
+
+  #ifdef ENABLE_STATE_SAVE
+    // Check for state changes
+    sprintf(current_state, "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d", mode, strip.getMode(), ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue);
+
+    if (strcmp(current_state, last_state) != 0) {
+      // DBG_OUTPUT_PORT.printf("STATE CHANGED: %s / %s\n", last_state, current_state);
+      strcpy(last_state, current_state);
+      time_statechange = millis();
+      state_save_requested = true;
+    }
+    if (state_save_requested && time_statechange + timeout_statechange_save <= millis()) {
+      time_statechange = 0;
+      state_save_requested = false;
+      writeEEPROM(256, 32, last_state); // 256 --> last_state (reserved 32 bytes)
+      EEPROM.commit();
+    }
+  #endif
+}


adding comments

adding comments

--- Arduino/Vendomatic/Vendomatic.ino
+++ Arduino/Vendomatic/Vendomatic.ino
@@ -39,7 +39,8 @@
 void checkCoinReader() {

   // this function needs to be called frequently or it may miss coins!
-  // might be worth adding it to a timer. Although it does need millis().
+  // might be worth adding it to a timer (although it does need millis()
+  // which may be unreliable from within a timer).

   int creditadded = coinReader.checkCoins();


Spelling_correction

--- working_directory/arduino_codes/arduino1/arduino1.ino
+++ working_directory/arduino_codes/arduino1/arduino1.ino
@@ -112,7 +112,7 @@
 		flag_12v_brownout_detected = 1;
 	}
 	else{
-		// turn_on_dynamixel(); //COMMENT LETER
+		// turn_on_dynamixel(); //COMMENT LATER
 		flag_12v_brownout_detected = 0;
 	}
 }


added handshaking functionality to arduino2.ino

--- working_directory/arduino_codes/arduino2/arduino2.ino
+++ working_directory/arduino_codes/arduino2/arduino2.ino
@@ -58,9 +58,9 @@
     _start_byte_ = Serial.read();
     command = Serial.read();
     parameter = Serial.read();
-
+
     if(_start_byte_ == start_byte) {
-      // _blink_();
+      _blink_();
       Serial.write(OKAY_CHARACTER);

       if(command == handshake_command) {


beta version, works with gps, wrong DD conversion

--- LART1.ino
+++ LART1.ino
@@ -2,8 +2,9 @@
 #include <LibAPRS.h>
 #include <TinyGPSplus.h>
 #include <DRA818.h>
-
-#define VERSION "Beta-0.93"
+#include <SoftwareSerial.h>
+
+#define VERSION "Beta-0.96g"

 #define ADC_REFERENCE REF_5V

@@ -20,7 +21,7 @@

 #define NOP __asm__ __volatile__("nop\n\t")

-int beacon_init_count = 10 ;
+int beacon_init_count = 100 ;

 unsigned long update_beacon = UPDATE_BEACON_INIT ;

@@ -32,7 +33,15 @@
 LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7 , 3, POSITIVE);
 #endif

-DRA818 dra(&Serial, PTT);
+// GPS setup
+
+TinyGPSPlus gps ;
+
+// DRA818 setup
+#define DRA_RXD A1
+#define DRA_TXD A2
+SoftwareSerial dra_serial(DRA_RXD,DRA_TXD);
+DRA818 dra(&dra_serial, PTT);

 boolean gotPacket = false ;
 int recv_count = 0 ;
@@ -102,7 +111,10 @@
    lcd.print("-") ;
    lcd.print(SSID) ;
 #endif
-   Serial.begin(9600) ;
+
+   dra_serial.begin(9600);
+   Serial.begin(4800) ;
+
    mydelay(2000UL) ;
 #ifdef OPTION_LCD
    lcd.clear();
@@ -168,43 +180,76 @@

 }

+char  lat[] =  "0000.00N" ;
+char  lon[] = "00000.00W" ;
+int h = 0 ;

 void loop()
 {

+
+   while(Serial.available() > 0 ) {
+       if(gps.encode(Serial.read())) {
+           if( gps.location.isValid()) {
+
+               // latitude
+               if ( gps.location.rawLat().negative ) {
+                   dtostrf(-100* gps.location.lat(),7,2,lat) ;
+                   lat[7] = 'S';
+               } else {
+                   dtostrf(100*gps.location.lat(),7,2,lat) ;
+                   lat[7] = 'N';
+               }
+               // longitude
+               if ( gps.location.rawLng().negative ) {
+                   dtostrf(-100*gps.location.lng(),8,2,lon) ;
+                   lon[8] = 'W';
+               } else {
+                   dtostrf(100*gps.location.lng(),8,2,lon) ;
+                   lon[8] = 'E';
+               }
+
+           }
+
+           // altitude
+           if ( gps.altitude.isValid() ) {
+               h = (int) gps.altitude.meters() ;
+           }
+
+       }
+   }

    if ( millis() - lastupdate > update_beacon ) {
      lastupdate = millis() ;
      if ( beacon_init_count-- <= -1 ) {
         update_beacon = UPDATE_BEACON ;
      }
-     // this sends a fixed location only
-     // beta beta beta
-     // dublin QTH
      // const char * lat =  "3742.44N" ;
      // const char * lon = "12157.54W" ;
      //
-     // igate
-     const char * lat =  "3740.91N" ;
-     const char * lon = "12146.05W" ;
-     int h = 0 ;
-
-#ifdef OPTION_LCD
-     lcd.clear();
-     lcd.print(F("sending packet"));
-#endif
-     locationUpdate(lat,lon,h,1,0,0) ;
-     // mydelay(250UL);
-     // dra.setPTT(LOW);
-     sent_count++ ;
-#ifdef OPTION_LCD
-     lcd.clear();
-     lcd.print(F("sent: ")) ;
-     lcd.print(sent_count) ;
-     lcd.setCursor(0,1);
-     lcd.print(F("recv: ")) ;
-     lcd.print(recv_count) ;
-#endif
+
+     if ( gps.location.isValid() )  {
+#ifdef OPTION_LCD
+         lcd.clear();
+         lcd.print(F("sending packet"));
+#endif
+         locationUpdate(lat,lon,h,1,0,0) ;
+         // mydelay(250UL);
+         // dra.setPTT(LOW);
+         sent_count++ ;
+#ifdef OPTION_LCD
+         lcd.clear();
+         lcd.print(F("s: ")) ;
+         lcd.print(sent_count) ;
+         lcd.print(F(" r: ")) ;
+         lcd.print(recv_count) ;
+         lcd.setCursor(0,1);
+         lcd.print(lat) ;
+#endif
+     } else {
+         lcd.clear();
+         lcd.print(F("gps not ready")) ;
+     }
    }

    processPacket() ;


Closes #2

Closes #2

--- LART1.ino
+++ LART1.ino
@@ -34,7 +34,7 @@
 #include "DRA818.h"
 #include "Log.h"

-#define VERSION "Beta-0.999a"
+#define VERSION "Beta-0.999b"
 #define ADC_REFERENCE REF_5V

 // sets PTT pin (don't change, the pin is used by Port Manipulation later on)


Add test code in main loop

Add test code in main loop

I'm kind of in the middle of using this stuff, but it works and i want
to get everything pushed up to remote master so I'm going ahead and
commiting it for now. I'll pull it out when I write the main control
loop stuff (after the sound).

--- CarpetLedLogic/CarpetLedLogic.ino
+++ CarpetLedLogic/CarpetLedLogic.ino
@@ -33,6 +33,51 @@

    clock = millis();

+   AudioBoard::pollFrequencies( clock );
+
+   if ( true ) {
+      Serial.println("millis");
+      Serial.println( clock );
+      Serial.println("output");
+      Serial.println( AudioBoard::bin_low );
+      Serial.println( AudioBoard::bin_mid );
+      Serial.println( AudioBoard::bin_high );
+      Serial.println("input");
+      Serial.println(AudioBoard::Frequencies_Mono[0]);
+      Serial.println(AudioBoard::Frequencies_Mono[1]);
+      Serial.println(AudioBoard::Frequencies_Mono[2]);
+      Serial.println(AudioBoard::Frequencies_Mono[3]);
+      Serial.println(AudioBoard::Frequencies_Mono[4]);
+      Serial.println(AudioBoard::Frequencies_Mono[5]);
+      Serial.println(AudioBoard::Frequencies_Mono[6]);
+   }
+
+   static const CRGBPalette16 clr( CRGB::Red, CRGB::Black );
+
+   // for ( int j = 0; j < NUM_MEGABAR_LEDS; ++j ) {
+   //    carpet->megabarLeds[ j ] = CRGB::Green;
+   // }
+   // if ( carpet->button->isDown() ) {
+   //    for ( int j = 0; j < NUM_MEGABAR_LEDS; ++j ) {
+   //       carpet->megabarLeds[ j ] = CRGB::Red;
+   //    }
+   // } else {
+   //    uint16_t val = scaleTo255( carpet->pot->read(), 1024, 0 );
+   //    for ( int j = 0; j < NUM_MEGABAR_LEDS; ++j ) {
+   //       carpet->megabarLeds[ j ] = CHSV( val, 255, 255 );
+   //    }
+   // }
+   for ( int j = 0; j < 7; ++j ) {
+      carpet->ropeLeds[ NEO1_OFFSET - 1 - j ] = ColorFromPalette( clr, scaleTo255( AudioBoard::Frequencies_Mono[j], 1024, 0 ) );
+   }
+   carpet->ropeLeds[ NEO1_OFFSET - 8 ] = ColorFromPalette( clr, AudioBoard::getLow() );
+   carpet->ropeLeds[ NEO1_OFFSET - 9 ] = ColorFromPalette( clr, AudioBoard::getMid() );
+   carpet->ropeLeds[ NEO1_OFFSET - 10 ] = ColorFromPalette( clr, AudioBoard::getHigh() );
+
+   // for ( int j = 0; j < NEO1_OFFSET; ++j ) {
+   //    carpet->ropeLeds[ j ] = CHSV( scaleTo255( carpet->pot->read(), 1024, 0 ), 255, 255 );
+   // }
+
    // read encoder
    // based on diff, switch between existing light shows


removing unnecessary files

removing unnecessary files

--- src/elm_clk.ino
+++ src/elm_clk.ino
@@ -7,7 +7,6 @@
 #include <OneButton.h>
 #include <Time.h>
 #include <MCP79412RTC.h>
-#include "pitches.h"
 #include "SevenSegController.h"

 // ---------------------- //
@@ -187,22 +186,6 @@
 	delay(10);
 }

-void playSong()
-{
-  int melody[] = {NOTE_A6, NOTE_A6,NOTE_B6, NOTE_G6, NOTE_A6,0, NOTE_B6, NOTE_C7, NOTE_B6, NOTE_G6, NOTE_A6, NOTE_B6, NOTE_C7, NOTE_B6, NOTE_A6, NOTE_G6, NOTE_A6};
-  int noteDurations[] = {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
-
-  for (int thisNote = 0; thisNote < 16; thisNote++)
-  {
-    int noteDuration = 1000/noteDurations[thisNote];
-    tone(A2, melody[thisNote],noteDuration);
-    int pauseBetweenNotes = noteDuration * 1.30;
-    delay(pauseBetweenNotes);
-    noTone(A2);
-  }
-}
-
-
 // ---------------------- //
 //  RTC test functions
 // ---------------------- //