/*
 * ---------------------------------------------------
 * ESP-WROOM WATCH v1.00 2017.04.01 @uzuran_n
 * ESP-WROOM-02 + Adafruit SSD1306 128x32 OLED Display
 * ---------------------------------------------------
 * FUNCTION 1: ADJUST TIME by NTP
 * FUNCTION 2: TWITTER - CHECK LAST MENTION
 * FUNCTION 3: TWITTER - にゃーん
 * FUNCTION 4: BATTERY
 * ---------------------------------------------------
 */

#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include <Ticker.h>
Ticker ticker1;

#include <Stewitter.h>
Stewitter twitter("-- your TOKEN here --");

volatile int ti = 0;
volatile int ss = 0;
volatile int mm = 0;
volatile int hh = 0;
volatile int menuNo = 0;
volatile boolean dispTimeEnable = true;
volatile boolean reWriteTimeEnable = true;
volatile boolean startinWiFi = false;
volatile float batt_rv;
volatile float batt;

String string1 = String("");
boolean network = 0;

// "network 0" (home)
char ssid_0[] = "-- SSID(home) here --";  //  your network SSID (name)
char pass_0[] = "-- PASS(home) here --";       // your network password

// "network 1" (mobile)
char ssid_1[] = "-- SSID(mobile) here --";  //  your network SSID (name)
char pass_1[] = "-- PASS(mobile) here --";       // your network password

unsigned int localPort = 2390;      // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
 *  Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;

// If using software SPI (the default case):
#define OLED_CS    16
#define OLED_RESET 14
#define OLED_DC    12
#define OLED_CLK   13
#define OLED_MOSI  15
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

//Uncomment this block to use hardware SPI
/*
#define OLED_DC     12
#define OLED_CS     15
#define OLED_RESET  16
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);
*/

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

extern "C" {
#include "user_interface.h"
}

void setup()
{
        delay(200);
        
        batt_rv = system_adc_read();
        batt = batt_rv * 1.055 / 100;
        if(batt < 3.50)
        {
                ESP.deepSleep(600 * 1000 * 1000 , WAKE_RF_DISABLED);
                delay(1000);
        }
        
        // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
        display.begin(SSD1306_SWITCHCAPVCC);
        // init done
        
        // Show image buffer on the display hardware.
        // Since the buffer is intialized with an Adafruit splashscreen
        // internally, this will display the splashscreen.
        display.display();
        delay(2000);
      
        // Clear the buffer.
        display.clearDisplay();
        
        ticker1.attach_ms(100, interrupt1);

        pinMode(4, INPUT);
        pinMode(5, INPUT);
        
        Serial.begin(9600);
        Serial.println();
        Serial.println();
        
        string1 = "network 0";
        while(true)
        {
                if(digitalRead(5) == 0)
                {
                        string1 = "";
                        delay(80);
                        while(digitalRead(5) == 0)
                        {
                                delay(3);
                        }
                        network ^= 1;
                        if(network == 0){
                                string1 = "network 0";
                        }
                        else{
                                string1 = "network 1";
                        }
                        delay(80);
                }
                if(digitalRead(4) == 0)
                {
                        string1 = "";
                        delay(80);
                        while(digitalRead(4) == 0)
                        {
                                delay(3);
                        }
                        
                        string1 = "selected";
                        delay(1000); //wait while displaying result
                        string1 = "";
                        break;
                }
                delay(2);
        }
        
        // We start by connecting to a WiFi network
        startinWiFi = true;
        Serial.print("Connecting to ");
        if(network == 0)
        {
                Serial.println(ssid_0);
                WiFi.begin(ssid_0, pass_0);
        }
        else
        {
                Serial.println(ssid_1);
                WiFi.begin(ssid_1, pass_1); 
        }
        while (WiFi.status() != WL_CONNECTED)
        {
                delay(500);
                Serial.print(".");
        }
        Serial.println("");
        Serial.println("WiFi connected");
        Serial.println("IP address: ");
        Serial.println(WiFi.localIP());
        Serial.println("Starting UDP");
        udp.begin(localPort);
        Serial.print("Local port: ");
        Serial.println(udp.localPort());
        startinWiFi = false;

        EEPROM.begin(100);
}

void interrupt1()
{
        static int i;
        
        if(reWriteTimeEnable)
        {
                ++ti;
                if(ti == 10)
                {
                        ti = 0;
                        ++ss;
                }
                if(ss == 60)
                {
                        ss = 0;
                        ++mm;
                }
                if(mm == 60)
                {
                        mm = 0;
                        ++hh;
                }
                if(hh == 24)
                {
                        hh = 0;
                }
        }
        
        display.setTextColor(WHITE);
        display.setTextSize(2);
        display.clearDisplay();
        display.setCursor(0,0);
        display.print(hh / 10);
        display.print(hh % 10);
        if(ti < 5)
        {
                display.print(":");
        }
        else
        {
                display.print(" ");
        }
        display.print(mm / 10);
        display.print(mm % 10);

        if(startinWiFi == true)
        {
                     if(i <  2){string1 = "";}
                else if(i <  4){string1 = ".";}
                else if(i <  6){string1 = "..";}
                else if(i <  8){string1 = "...";}
                else if(i < 10){string1 = "....";}
                else if(i < 12){string1 = ".....";}
                else if(i < 14){string1 = "......";}
                else if(i < 16){string1 = ".......";}
                else if(i < 18){string1 = "........";}
                else if(i < 20){string1 = ".........";}
                else if(i < 22){string1 = "..........";}
                i++;
                if(i == 23)
                {
                        i = 0;
                }
        }
        display.setCursor(0,16);
        display.print(string1);
        display.display();
        
        batt_rv = system_adc_read();
        batt = batt_rv * 1.055 / 100;
}

void getTime()
{
        //get a random server from the pool
        WiFi.hostByName(ntpServerName, timeServerIP); 
      
        sendNTPpacket(timeServerIP); // send an NTP packet to a time server
        // wait to see if a reply is available
        delay(1000);
        
        int cb = udp.parsePacket();
        if (!cb)
        {
                Serial.println("no packet yet");
                
                // ******* modified *******
                string1 = "no packet";
        }
        else
        {
                Serial.print("packet received, length=");
                Serial.println(cb);
                
                // ******* modified *******
                string1 = "received!";
                
                // We've received a packet, read the data from it
                udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
            
                //the timestamp starts at byte 40 of the received packet and is four bytes,
                // or two words, long. First, esxtract the two words:
            
                unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
                unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
                // combine the four bytes (two words) into a long integer
                // this is NTP time (seconds since Jan 1 1900):
                unsigned long secsSince1900 = highWord << 16 | lowWord;
                Serial.print("Seconds since Jan 1 1900 = " );
                Serial.println(secsSince1900);
            
                // now convert NTP time into everyday time:
                Serial.print("Unix time = ");
                // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
                const unsigned long seventyYears = 2208988800UL;
                // subtract seventy years:
                unsigned long epoch = secsSince1900 - seventyYears;
                // print Unix time:
                Serial.println(epoch);
            
            
                // print the hour, minute and second:
                Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
                Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)    
                Serial.print(':');
                if ( ((epoch % 3600) / 60) < 10 )
                {
                        // In the first 10 minutes of each hour, we'll want a leading '0'
                        Serial.print('0');
                }
                Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
                Serial.print(':');
                if ( (epoch % 60) < 10 )
                {
                        // In the first 10 seconds of each minute, we'll want a leading '0'
                        Serial.print('0');
                }
                Serial.println(epoch % 60); // print the second
            
                // ******* modified *******
                reWriteTimeEnable = false;
                        
                        hh = (epoch  % 86400L) / 3600;
                        hh += 9; //JST
                        if(hh > 23)
                        {
                                hh -= 24;
                        }
                        mm = (epoch  % 3600) / 60;
                        ss = epoch  % 60;
                        
                reWriteTimeEnable = true;
        }
}
void loop()
{
        int i;
        String string2 = "";
        String string3 = "";
        String string4 = "";
        
        if(digitalRead(5) == 0)
        {
                string1 = "";
                delay(80);
                while(digitalRead(5) == 0)
                {
                        delay(3);
                }
                
                ++menuNo;
                if(menuNo == 4)
                {
                        menuNo = 0;
                }
        }
        
        if(menuNo == 0)
        {
                string1 = "adj time";
                if(digitalRead(4) == 0)
                {
                        string1 = "";
                        delay(80);
                        while(digitalRead(4) == 0)
                        {
                                delay(3);
                        }
                        
                        string1 = "connect";
                        getTime();
                        delay(1000); //wait while displaying result
                }
        }
        else if(menuNo == 1)
        {
                string1 = "chk ment";
                if(digitalRead(4) == 0)
                {
                        string1 = "";
                        delay(80);
                        while(digitalRead(4) == 0)
                        {
                                delay(3);
                        }
                        
                        string1 = "connect";
                        if (twitter.lastMention())
                        {
                                int status = twitter.wait();
                                if (status == 200)
                                {
                                        Serial.println(twitter.response());
                                        string3 = String(twitter.response());
                                        string2 = String(string3.substring(0, 4));
                                        string2 = String(string2 + " ");
                                        string2 = String(string2 + string3.substring(4, 8));
                                        string2 = String(string2 + " ");
                                        string2 = String(string2 + string3.substring(8, 12));
                                        string2 = String(string2 + " ");
                                        string2 = String(string2 + string3.substring(34));
                                        string1 = String(string2);
                                        delay(1000);
                                        
                                        for(i = 0; i < 40; i++)
                                        {
                                                delay(333);
                                                string1 = string1.substring(1);
                                        }
                                }
                                else
                                {
                                        Serial.print("failed : code ");
                                        Serial.println(status);
                                        string1 = String(status);
                                        delay(1000);
                                }
                        }
                        else
                        {
                                Serial.println("connection failed.");
                                string1 = "failed";
                                delay(1000);
                        }
                }
        }
        else if(menuNo == 2)
        {
                uint8_t nyanCount;
                char buff[18];
                
                string1 = "nya-n";
                if(digitalRead(4) == 0)
                {
                        string1 = "";
                        delay(80);
                        while(digitalRead(4) == 0)
                        {
                                delay(3);
                        }
                        
                        nyanCount = EEPROM.read(0);
                        Serial.println(nyanCount);
                        string2 = String("にゃーん (");
                        string2 = String(string2 + (nyanCount / 10));
                        string2 = String(string2 + (nyanCount % 10));
                        string2 = String(string2 + ")");
                        string2.toCharArray(buff, 18);
                        
                        string1 = "connect";
                        if (twitter.post(buff))
                        {
                                int status = twitter.wait();
                                if (status == 200)
                                {
                                        Serial.println(twitter.response());
                                        string1 = "tweeted!";
                                        delay(1000);

                                        nyanCount++;
                                        if(nyanCount >= 100)
                                        {
                                                nyanCount = 0;
                                        }
                                        EEPROM.write(0, nyanCount);
                                        EEPROM.commit();
                                }
                                else
                                {
                                        Serial.print("failed : code ");
                                        Serial.println(status);
                                        string1 = String(status);
                                        delay(1000);
                                }
                        }
                        else
                        {
                                Serial.println("connection failed.");
                                string1 = "failed";
                                delay(1000);
                        }
                }
        }
        else if(menuNo == 3)
        {
                string2 = "b ";
                string3 = String(batt);
                string4 = "V";
                string1 = String(string2 + string3 + string4);
        }
        
        if(batt < 3.30)
        {
                for(i = 0; i < 60; i++)
                {
                        string1 = "low bat"; 
                        delay(500);
                        string1 = "";
                        delay(500);
                }               
                ESP.deepSleep(600 * 1000 * 1000 , WAKE_RF_DISABLED);
                delay(1000);
        }
        delay(2);
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
{
        Serial.println("sending NTP packet...");
        // set all bytes in the buffer to 0
        memset(packetBuffer, 0, NTP_PACKET_SIZE);
        // Initialize values needed to form NTP request
        // (see URL above for details on the packets)
        packetBuffer[0] = 0b11100011;   // LI, Version, Mode
        packetBuffer[1] = 0;     // Stratum, or type of clock
        packetBuffer[2] = 6;     // Polling Interval
        packetBuffer[3] = 0xEC;  // Peer Clock Precision
        // 8 bytes of zero for Root Delay & Root Dispersion
        packetBuffer[12]  = 49;
        packetBuffer[13]  = 0x4E;
        packetBuffer[14]  = 49;
        packetBuffer[15]  = 52;
      
        // all NTP fields have been given values, now
        // you can send a packet requesting a timestamp:
        udp.beginPacket(address, 123); //NTP requests are to port 123
        udp.write(packetBuffer, NTP_PACKET_SIZE);
        udp.endPacket();
}