/*
 ESP8266 MQTT 

Version 2017-08-15
* using decimal values (0..255) for mode,speed, brightness  !!
* less use of ws2812fx.stop();
* ws2812fx.start() only when a mode is recieved.

this sketch subscibes 2 MQTT topics:

topic: "huette/clubraum/000/ws2812tonne/actuators/frame"
- receive a binary MQTT message with seperate RGB values for all pixels
  (1 frame / ein Bild ) and control Neopixel LEDs
  3 bytes per pixel (r,g,b) 

topic: "huette/clubraum/000/ws2812tonne/actuators/set_pixel"
- receive a  command (ascii)
 possible commands:
 
 0-n #RRGGBB  (set one pixel, disable effects)
 255 #RRGGBB  (set all pixels, disable effects)
 mode 0-46    (WS2812FX mode, enable effects)
 speed 0-255
 brightness 0-255
 color #RRGGBB

 
*/

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>
#include <WS2812FX.h>

#include "conf.h"

// I moved this to conf.h
//const char* ssid = "XXXXXXX";
//const char* password = "XXXXXXX";
//const char* mqtt_server = "XXXX";


WiFiClient espClient;
PubSubClient client(espClient);

WS2812FX ws2812fx = WS2812FX(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int r,g,b;

byte framebuffer[NUMPIXELS*3];
String stringPixel, stringFrame, stringIntopic ;
bool fx_is_active;

void printModes() {
  Serial.println(F("Supporting the following modes: "));
  Serial.println();
  for(int i=0; i < ws2812fx.getModeCount(); i++) {
    Serial.print(i);
    Serial.print(F("\t"));
    Serial.println(ws2812fx.getModeName(i));
  }
  Serial.println();
}



void setup() {
  //pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  pixels.begin();
  setup_wifi();
  client.setServer(mqtt_server, 1883);
 
  client.subscribe("inTopic");
  client.subscribe("inTopic2");
  
  client.setCallback(callback);

  stringPixel = String(inTopic2);
  stringFrame = String(inTopic);

  ArduinoOTA.setHostname("saturnring"); // give an name to our module
  ArduinoOTA.begin(); // OTA initialization


  ws2812fx.init();
  ws2812fx.setBrightness(30);
  ws2812fx.setSpeed(200);
  ws2812fx.setColor(0x220022);
  ws2812fx.setMode(9);
  ws2812fx.start();
  fx_is_active = true;

  printModes();
 
  
} //setup

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
 // Serial.print("BUILTIN_LED Value: ");
 // Serial.println(BUILTIN_LED);
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.softAPdisconnect(true);
  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    
    delay(500);
    Serial.print(".");
    pixels.setPixelColor(0, pixels.Color(50,0,0));  
    pixels.show(); 
  
    //Serial.println("trying SSID2..");
    //pixels.setPixelColor(0, pixels.Color(50,50,0));
    //WiFi.begin(ssid2, password2);
    
  }

  Serial.println("");
  Serial.println("WiFi connected");
  pixels.setPixelColor(0, pixels.Color(0,50,0));  
  pixels.show(); 
  delay(500);
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  client.subscribe(inTopic);
  client.setCallback(callback);
  
} //setup_wifi



void parse_mqtt_message( byte* payload, unsigned int length){
int splitat;
// Einmal die ganze Payload durcharbeiten...
  String s = "";
  for(int i = 0; i < length; i++) {
    // und Seriell ausgeben
   s += (char)payload[i];
  //  Serial.println((char)payload[i]);
   if (isWhitespace((char)payload[i])) {
    splitat = i;
    i = length;
    }
    
  }
    String Numberstring = "";
    String Colorstring = "";
    for(int i = 0; i < splitat; i++) {
       Numberstring += (char) payload[i];   
    }

    for (int i = (splitat + 1); i < length; i++) {
      Colorstring += (char) payload[i];
    }
 
//Colorstring contains something like = "#00ff00" or "00ff00"
// you need to convert it to 0,255,0 and insert it to the two calls below
// Am ende Newline.
   int intcolors=(int) strtol(&Colorstring[1],NULL,16);
   int r = intcolors >> 16;
   int g = intcolors >> 8 & 0xFF;
   int b = intcolors & 0xFF;

  
  Serial.print("Numberstring:" + Numberstring + " Colorstring:" + Colorstring + " intcolors:");
  Serial.print(intcolors);
  Serial.print(" " );
  Serial.print( Numberstring.toInt() );
  Serial.print(" " );
  Serial.println( Colorstring.toInt() );
  
  if(Numberstring == "mode") {
     ws2812fx.setMode(Colorstring.toInt());
     if(! fx_is_active){
       ws2812fx.start();
       fx_is_active = true;
     }
  }

  else if(Numberstring == "speed") {
     ws2812fx.setSpeed(Colorstring.toInt());
   
  }
  
  else if(Numberstring == "brightness") {
     ws2812fx.setBrightness(Colorstring.toInt());
   
  }

  else if(Numberstring == "color") {
     ws2812fx.setColor(intcolors);
  
  }
  else if(Numberstring.toInt() == 255) {
    //set all pixels to the same color
    if(fx_is_active){
      ws2812fx.stop();
      fx_is_active = false;
    }
    for(int i = 0; i < NUMPIXELS; i++) {
      pixels.setPixelColor(i, pixels.Color(r,g,b)); 
    }
    pixels.show(); 
  }
  
  // needs testing:
  // toInt returns 0 if it is not a number !
  else if(Numberstring.toInt() >= 0 && Numberstring.toInt() < NUMPIXELS)
  {
    if( fx_is_active){
    ws2812fx.stop();
    fx_is_active = false;
    }
    pixels.setPixelColor(Numberstring.toInt(), pixels.Color(r,g,b)); 
    pixels.show(); // This sends the updated pixel color to the hardware.
  }
  
}  //parse_mqtt_message

void writeframe(byte* payload, unsigned int length){
  //Serial.print("TOPIC=frame");
  if(fx_is_active){
    ws2812fx.stop();
    fx_is_active = false;
  }
  //write bytes to framebuffer
  for (int i = 0; i < (length) ; i++) {
   // Serial.print((char)payload[i]);
   // Serial.print(" ");
   if (i < NUMPIXELS*3)
   {
    framebuffer[i] = payload[i];
   }
  }
  
  //write frame to LEDs
  int j=0;
  for(int i = 0; i < NUMPIXELS*3 ; i=i+3) {
    //Serial.print(" ");
    //Serial.print(j);
    //Serial.print(":");
      r = framebuffer[i];
      g = framebuffer[i+1];
      b = framebuffer[i+2];
     //Serial.print(r);
     //Serial.print(g);
     //Serial.print(b);
      pixels.setPixelColor(j, pixels.Color(r,g,b)); 
      j++;
  }
  //Serial.println();
  pixels.show();  
} //writeframe


void callback(char* topic, byte* payload, unsigned int length) {

  //Serial.print("Message arrived [");
  //Serial.print(topic);
  //Serial.print("] ");
  //Serial.print("length:");
  //Serial.print(   length );

  stringIntopic = String(topic);
  if (stringIntopic == stringPixel ){

    //Serial.print("TOPIC=setpixel");
    parse_mqtt_message(payload,length);
  }

  if (stringIntopic == stringFrame ){
    writeframe(payload,length);
    
  }
  
  

 

} //callback

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("")) {
      Serial.println("connected");
      
      // Once connected, publish an announcement...
      client.publish(outTopic, "hello world");
      // ... and resubscribe
      client.subscribe(inTopic);
      client.subscribe(inTopic2);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
} //reconnect

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  ArduinoOTA.handle(); 
   delay(20);

   ws2812fx.service();

   
  }  //loop