/**
 ** 2 line LCD 1602 via I2C
 ** DS3231 RTC clock
 ** DHT11 Temperature meter
 ** PIR sensor
 ** WS2812B Segment display
 **
 ** Arduino analog input 5 - I2C SCL CLOCK ( BROWN WIRE ) <- note for me
 ** Arduino analog input 4 - I2C SDA DATA  ( WHITE WIRE ) <- note for me
 **
 ** I2C scanner output:
 ** 0x23 BH1750 light level meter sensor
 ** 0x27 I2C to LCD
 ** 0x68 DS3231 RTC clock
 ** 0x57 ?? temperature?
 **/

#include <Wire.h>
#include <FastLED.h>
#include "DHT.h"
#include <Time.h>
#include "LiquidCrystal_I2C.h"
#include "DS3231.h"
#include "BH1750.h"

#define Sprintln(a)		(Serial.println(a))
#define Sprint(a)		(Serial.print(a))
//#define Sprintln(a)		
//#define Sprint(a)		
#define seconds()		((unsigned long)millis()/1000)
#define minutes()		((unsigned int)seconds()/60)
#define hours()			((unsigned int)minutes()/60)

#define	DATA_PIN	 8
#define	BTN1_PIN	11
#define	BTN2_PIN	10
#define	BTN3_PIN	 9

// PIR Sensor
#define PIR_PIN	 A7
#define LED_PIN 13			// show activity
unsigned int pir_active = 0;

const char *WeekDay[7] = { "Nedela", "Pondelok", "Utorok", "Streda", "Stvrtok", "Piatok", "Sobota" };

// DHT11 Temperature
DHT dht(3, DHT11);
byte hum, temp;			// Not able to measure outside temperature below zero

// BH1750 Light Meter
BH1750 lightMeter;
uint16_t lux;

// WS2812b RGB LED STRIP
// fire + clock 14 * 4 + 3 * 4 = 68 + 72 = 140
int		COLOR_INDEX		= 128;
int		BRIGHTNESS 		= 2;		// variable
int		BRIGHTNESS_ADD	= 0;
#define	BRIGHTNESS_ON	8
#define	BRIGHTNESS_MIN	2
#define	BRIGHTNESS_MAX	50
#define	NUM_LEDS 		68		// fire: 3*24 = 72, seg disp: 4 * 14 + 3 * 4 = 68
#define SEG_DOTS		33		// 33 and 34
#define SEG_DECIMAL		32		// 24.5°C
#define SEG_DEGREE		53		//	24.5°C
CRGB leds[NUM_LEDS];
CRGBPalette16 gPal;

// LCD 1602
LiquidCrystal_I2C lcd(0x27, 16, 2);	// <<----- Add your address here.  Find it from I2C Scanner, 0x27, 0x3F
// custom chars names
#define BYTE_Lx 0
#define BYTE_Left 127	// standard arrow
#define BYTE_Right 126	// standard arrow
#define BYTE_DEGREE	223	// degree celsius
// --- Define their own characters for the LCD:
byte charLx[8] = {0x00, 0x10, 0x10, 0x10, 0x15, 0x12, 0x1d, 0x00 };
// not used byte charC[8] = {0x18,0x1a,0x05,0x04,0x04,0x05,0x02,0x00};


// SEGMENT clock
#define SEG_SEGMENTS	4	// 0,1,2,3
#define SEG_SEG_SIZE	18	// leds from one seg char to another

boolean SEG_FONT[][14] = {
//	 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},	// 0
	{0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},	// 1
	{1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1},	// 2
	{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1},	// 3
	{0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1},	// 4
	{1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1},	// 5
	{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},	// 6
	{1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},	// 7
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},	// 8
	{1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1},	// 9
	{1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0},	// C
	{1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1},	// % left half
	{1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}	// % right half
};


time_t t;
int i;


/**1234567890123456**
 * Ne 13.11.  10:30 * 1.
 *    2016   22.5°C *
 ********************
 * Ne 13.11.  10:30 * 2.
 * 123456x   22.5°C *
 ********************
 * Pondelok   12:12 * 3.
 * 13.11.16  22.5°C *
 ********************/

void lcd_display(byte screen) {
	lcd.clear();
	switch(screen) {
		case 1:
			lcd.print( (char *) WeekDay[weekday(t) - 1][0]);
			lcd.print( (char *) WeekDay[weekday(t) - 1][1]);
			lcd.print(" ");
			lcd_number(day(t), 2, '-');
			lcd.print(".");
			lcd_number(month(t), 2, '-');
			lcd.print(".");
			lcd_number(hour(t), 2, '-');
			lcd.print(":");
			lcd_number(minute(t), 2, '-');
			lcd.setCursor(1,4);
			lcd.print(year(t) - 2000, DEC);

			break;
		case 2:
			break;
		case 3:
			lcd.print( (char *) WeekDay[weekday(t) - 1]);
			lcd.setCursor(0, 1);
			lcd.print(day(t), DEC);
			lcd.print(".");
			lcd.print(month(t), DEC);
			lcd.print(".");
			lcd.print(year(t) - 2000, DEC);
			break;
		default:
			break;
	}
}


/*****  ******  ******  **  **  *****
**      **        **    **  **  **  **
 ****   *****     **    **  **  *****
    **  **        **    **  **  **
*****   ******    **     ****   **/
void setup() {
	byte sec, min, hr, wd, dy, mon, yr;

	pinMode(PIR_PIN, INPUT);
	pinMode(DATA_PIN, OUTPUT);

	Serial.begin(9600);
	lcd.init();
	Wire.begin();
	dht.begin();
	BRIGHTNESS = BRIGHTNESS_ON;

	lcd.createChar (BYTE_Lx, charLx);

	// Switch on the backlight
	lcd.backlight();
	lcd.clear();
	lcd.setCursor(4, 0);		lcd.print(F("Arduino"));				delay(600);

		readDS3231time(&sec, &min, &hr, &wd, &dy, &mon, &yr);
		setTime(hr, min, sec, dy, mon, 2000 + yr);

		// set the initial time here:
//		if (yr < 1) {
//			// DS3231  seconds, minutes, hours, wday, date, month, year
//			setDS3231time( 0,      27,    23,    7,   12,     6,   16);
//		}

	lcd.setCursor(2, 1);		lcd.print(F("WS2812 Clock"));			delay(600);

		FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
		FastLED.clear();

	lcd.setCursor(4, 0);		lcd.print(F(__TIME__));					delay(600);

		FastLED.setBrightness( BRIGHTNESS );
		fill_solid(leds, NUM_LEDS, CRGB::White);
		FastLED.show();

	lcd.setCursor(2, 1);		lcd.print(F(__DATE__));lcd.print(" ");	delay(100);

	FastLED.delay(500); // Sanity before start

	gPal = RainbowColors_p;

	// show leds on start
	for ( i = 0 ; i < NUM_LEDS ; i++ ) {
		leds[i] = ColorFromPalette( gPal, (255 / NUM_LEDS) * i, 250, LINEARBLEND);
		FastLED.show();
		FastLED.delay(30);
	}
	for ( i = 0 ; i < NUM_LEDS ; i++ ) {
		leds[i] = CRGB::Black;
		FastLED.show();
		FastLED.delay(30);
	}

	FastLED.show();
	FastLED.delay(500);
	delay(500);
	lcd.clear();

	// Set clock palette
	//gPal = CRGBPalette16( CRGB::Black, CRGB(255,0,0), CRGB::Orange, CRGB::Yellow);
	pir_active = 30;

	Sprintln(F("Setup finished."));
}




/**       ****    ****   *****
 **      **  **  **  **  **  **
 **      **  **  **  **  *****
 **      **  **  **  **  **
 ******   ****    ****   **/
void loop() {
	static int current_delay = 150;
	static int last_millis;		
	static int last_seconds;	boolean secondely	= false;
	static int last_minutes;	boolean minutely	= false;
	static int last_hours;		boolean hourly		= false;
	int h, m, ct, ch;	// current temperature, humidity

	static byte buttons;

	/** Check PIR (every 2 seconds)
	 * check time (hourly)
	 * check temp, hum (minute)
	 * check luxmeter (minute)
	 * if PIR active, turn display ON, turn leds HIGH
	 * adjust BRIGHTNESS according to ambient light
	 **/
	 
	secondely = (last_seconds < seconds() ? true : false);
	minutely = (last_minutes < minutes() ? true : false);
	hourly = (last_hours < hours() ? true : false);
	
	buttons = read_buttons(BTN1_PIN,BTN2_PIN,BTN3_PIN);

	t = now();
	fill_solid(leds, NUM_LEDS, CRGB::Black);

	// PIR
	if ( secondely ) { 									// once per every second
		if ( analogRead(PIR_PIN) > 400 ) {
			pir_active = ( pir_active > 0 ? (pir_active < 60 ? pir_active : 60) : (1000/current_delay)*10 ) + 1;		// increase from 10 to 60
		} else {
			pir_active = ( pir_active > 0 ? pir_active - 1 : 0 );		// decrease to 0
		}
//		Sprint("["); 		Sprint( millis() ); 		Sprintln("]");
	}

	if( buttons > 0 ) {
		Sprint(seconds());
		Sprint(F("  Buttons:  "));
		Sprintln(buttons);
		if (buttons == 100) {
			COLOR_INDEX += random(0,30);
		}
		if (buttons == 10) {
			COLOR_INDEX+=2;
		}
		if (buttons == 1) {
			COLOR_INDEX-=2;
		}
	}

	if ( minutely ) {
		lcd.clear();	// clear screen:-(
		// Date & Time:
		lcd.setCursor(0, 0);
		lcd.print( (char *) WeekDay[weekday(t) - 1]);
		lcd.print(" ");

		lcd.setCursor(8, 0);
		lcd.print(day(t), DEC);
		lcd.print(".");
		lcd.print(month(t), DEC);
		lcd.print(".");
		lcd.print(year(t) - 2000, DEC);

		dht.begin();
		for (i=0;i<10;i++) {
			ct = ct + (int) dht.readTemperature();
			ct = ct / 2;							// average
			readDS3231temperature(&hum);
			temp = (ct + hum) /2;					// average

			hum = (int) dht.readHumidity();
		}
		//temp = (abs(ct - temp) > 10 ? ct : (ct+temp)/2);
		Sprint(" B: ");
		Sprint(BRIGHTNESS);
		Sprint(" T: ");
		Sprint(temp);
		Sprint(" H: ");
		Sprintln(hum);

		lightMeter.begin();
		lux = lightMeter.readLightLevel();
	}

	// Pir status
	lcd.setCursor(9, 0);
	lcd.print( pir_active ? "*" : "-");

	if ( secondely ) {
		// Time
		lcd.setCursor(8, 1);	lcd_number(hour(t), 2, ' ');	// Hours
		lcd.setCursor(11, 1);	lcd_number(minute(t), 2, '0');	// Minutes

		Sprint(" B: ");
		Sprint(BRIGHTNESS);
		Sprint(" BA: ");
		Sprintln(BRIGHTNESS_ADD);
	}



	if ( minutes() % 2 == 0 ) {
		// DOTS : :
//		if ( millis() % 1000 < 500 ) {								// Every half second
//			// turn dots on
//			lcd.setCursor(10,1);	lcd.print(":");
//			lcd.setCursor(13,1);	lcd.print(":");
//			lcd_number(second(t), 2, '0');							// Seconds
//			leds[SEG_DOTS] = ColorFromPalette( gPal, COLOR_INDEX, 255, LINEARBLEND);
//			leds[SEG_DOTS+1] = ColorFromPalette( gPal, COLOR_INDEX, 255, LINEARBLEND);
//		} else {
//			// turn dots off
//			lcd.setCursor(10,1);	lcd.print(" ");
//			lcd.setCursor(13,1);	lcd.print(" ");
//			leds[SEG_DOTS] = CRGB::Black;
//			leds[SEG_DOTS+1] = CRGB::Black;
//		}
		// 14,32,50
//		Sprint(" ");
//		Sprint( round( (int) millis() % 1000 / 250 + 0.5F) );
		
		leds[14] = leds[15] = leds[16] = leds[17] = CRGB::Black;
		leds[32] = leds[33] = leds[34] = leds[35] = CRGB::Black;
		leds[50] = leds[51] = leds[52] = leds[53] = CRGB::Black;
		switch( round( (float) ( millis() % 1000 ) / 250 + 0.5F) ) {
			case 1:
				leds[15] = leds[16] = ColorFromPalette( gPal, COLOR_INDEX, 255, LINEARBLEND);
				break;
			case 2:
				leds[33] = leds[34] = ColorFromPalette( gPal, COLOR_INDEX, 255, LINEARBLEND);
				break;
			case 3:
				leds[51] = leds[52] = ColorFromPalette( gPal, COLOR_INDEX, 255, LINEARBLEND);
				break;
		}

		// display TIME:
		h = hour(t);
		m = minute(t);

		lcd.setCursor(0, 1);	lcd.print(lux, DEC);	lcd.write(BYTE_Lx);		lcd.print("  ");	// Light level

		seg_write( 0, (int) h / 10, CRGB::Black );
		seg_write( 1, (int) h % 10, CRGB::Black );
		seg_write( 2, (int) m / 10, CRGB::Black );
		seg_write( 3, (int) m % 10, CRGB::Black );
	} else {
		// Turn off the dots:
		leds[SEG_DOTS] = CRGB::Black;
		leds[SEG_DOTS+1] = CRGB::Black;
		if (seconds() % 60 < 30) {
			// display TEMPERATURE
			lcd.setCursor(0, 1);	lcd_number(temp, 4, ' ');	lcd.write(BYTE_DEGREE);		lcd.print("C");		// Temperature
			if ( temp >= 100 ) seg_write( 0, (int) temp / 100, (COLOR_INDEX == 128 ? CRGB::Green : CRGB::Black) );
			if ( temp >= 10 ) seg_write( 1, (int) temp / 10, (COLOR_INDEX == 128 ? CRGB::Green : CRGB::Black) );
			if ( temp >= 1 ) seg_write( 2, (int) temp % 10, (COLOR_INDEX == 128 ? CRGB::Green : CRGB::Black) );
			seg_write( 3, 10, CRGB::White );	// C
			leds[SEG_DEGREE] = CRGB::White;
		} else {
			// display HUMIDITY
			lcd.setCursor(0, 1);	lcd_number(hum, 4, ' ');	lcd.print("%");		// Humidity
			if ( hum >= 10 ) seg_write( 0, (int) hum / 10, (COLOR_INDEX == 128 ? CRGB::Blue : CRGB::Black) );
			if ( hum >= 1 ) seg_write( 1, (int) hum % 10, (COLOR_INDEX == 128 ? CRGB::Blue : CRGB::Black) );
			seg_write( 2, 11, CRGB::White );	// % - left half
			seg_write( 3, 12, CRGB::White );	// % - right half
		}
	}

	// Light saver:
	if ( pir_active > 0 ) {
		lcd.backlight();
		BRIGHTNESS_ADD = 1;
	} else {
		lcd.noBacklight();
		BRIGHTNESS_ADD = -1;
	}
	if ( BRIGHTNESS + BRIGHTNESS_ADD >= BRIGHTNESS_MIN && BRIGHTNESS + BRIGHTNESS_ADD <= BRIGHTNESS_MAX ) {
		BRIGHTNESS = BRIGHTNESS + BRIGHTNESS_ADD;
	} else {
		BRIGHTNESS_ADD = 0;
	}

	if ( secondely ) {
		last_seconds = seconds();
		last_minutes = minutes();
		last_hours = hours();
	}
	last_millis = millis();

	FastLED.setBrightness( BRIGHTNESS );
	FastLED.show();
	FastLED.delay( current_delay );
//	delay(current_delay);
}


// Write character at position
// use "leds" array
void seg_write(byte position, byte font_char, CRGB color) {
	byte j, strip_position;

	// strip pos = position * 18
	// for each of 7 segment display (14)
	for ( j = 0 ; j < 14 ; j++ ) 	{
		strip_position = position * SEG_SEG_SIZE + j;
		if ( strip_position < NUM_LEDS ) {
			if ( SEG_FONT[font_char][j] == 1 ) {
				if ( color.r == 0 && color.g == 0 && color.b == 0 ) {
					leds[strip_position] = ColorFromPalette( gPal, COLOR_INDEX, 255, LINEARBLEND);
				} else {
					leds[strip_position] = color;
				}
			} else {
				leds[strip_position] = CRGB::Black;
			}
		}
	}
}


// read_buttons(PIN1,PIN2,PIN3) and return 3digit number
// debounce button state
byte read_buttons( byte BTN1, byte BTN2, byte BTN3) {
	static byte last_buttons;		// button 000, 100, 010, 001, 011, 110, 101
	byte buttons = 0;
	boolean b1_state = digitalRead(BTN1);
	boolean b2_state = digitalRead(BTN2);
	boolean b3_state = digitalRead(BTN3);

	buttons += (b1_state ? 100 : 0);
	buttons += (b2_state ?  10 : 0);
	buttons += (b3_state ?   1 : 0);
	
	if ( last_buttons == buttons ) {
		return buttons;
	}
	last_buttons = buttons;
	return (0);
}


// countDigits( num) -- Count digits in a number
byte countDigits(int num) {
	byte count = 0;
	if (num < 10) return 1;
	if (num < 100) return 2;
	if (num < 1000) return 3;
	while(num) 	{
		num = num / 10;
		count++;
	}
	return count;
}


// lcd_number( number, number_size, pad) -- print ' ' padded number at cursor
void lcd_number(long number, uint8_t number_size, char pad) {
	while (number_size > countDigits(number)) {
		number_size--;
		lcd.write(pad);
	}
	lcd.print(number);
}

// End of file WS2812 Clock.ino

nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
GND5VSDASCLSQWRTCDS1307+
rtc:GND
rtc:5V
rtc:SDA
rtc:SCL
rtc:SQW
lcd:GND
lcd:VCC
lcd:SDA
lcd:SCL
p0:VDD
p0:DOUT
p0:VSS
p0:DIN
p1:VDD
p1:DOUT
p1:VSS
p1:DIN
p2:VDD
p2:DOUT
p2:VSS
p2:DIN
p3:VDD
p3:DOUT
p3:VSS
p3:DIN
p4:VDD
p4:DOUT
p4:VSS
p4:DIN
p5:VDD
p5:DOUT
p5:VSS
p5:DIN
p6:VDD
p6:DOUT
p6:VSS
p6:DIN
p7:VDD
p7:DOUT
p7:VSS
p7:DIN
p8:VDD
p8:DOUT
p8:VSS
p8:DIN
p9:VDD
p9:DOUT
p9:VSS
p9:DIN
p10:VDD
p10:DOUT
p10:VSS
p10:DIN
p11:VDD
p11:DOUT
p11:VSS
p11:DIN
p12:VDD
p12:DOUT
p12:VSS
p12:DIN
p13:VDD
p13:DOUT
p13:VSS
p13:DIN
p14:VDD
p14:DOUT
p14:VSS
p14:DIN
p15:VDD
p15:DOUT
p15:VSS
p15:DIN
p16:VDD
p16:DOUT
p16:VSS
p16:DIN
p17:VDD
p17:DOUT
p17:VSS
p17:DIN
p18:VDD
p18:DOUT
p18:VSS
p18:DIN
p19:VDD
p19:DOUT
p19:VSS
p19:DIN
p20:VDD
p20:DOUT
p20:VSS
p20:DIN
p21:VDD
p21:DOUT
p21:VSS
p21:DIN
p22:VDD
p22:DOUT
p22:VSS
p22:DIN
p23:VDD
p23:DOUT
p23:VSS
p23:DIN
p24:VDD
p24:DOUT
p24:VSS
p24:DIN
p25:VDD
p25:DOUT
p25:VSS
p25:DIN
p26:VDD
p26:DOUT
p26:VSS
p26:DIN
p27:VDD
p27:DOUT
p27:VSS
p27:DIN
p28:VDD
p28:DOUT
p28:VSS
p28:DIN
p29:VDD
p29:DOUT
p29:VSS
p29:DIN
p30:VDD
p30:DOUT
p30:VSS
p30:DIN
p31:VDD
p31:DOUT
p31:VSS
p31:DIN
p32:VDD
p32:DOUT
p32:VSS
p32:DIN
p33:VDD
p33:DOUT
p33:VSS
p33:DIN
p34:VDD
p34:DOUT
p34:VSS
p34:DIN
p35:VDD
p35:DOUT
p35:VSS
p35:DIN
p36:VDD
p36:DOUT
p36:VSS
p36:DIN
p37:VDD
p37:DOUT
p37:VSS
p37:DIN
p38:VDD
p38:DOUT
p38:VSS
p38:DIN
p39:VDD
p39:DOUT
p39:VSS
p39:DIN
p40:VDD
p40:DOUT
p40:VSS
p40:DIN
p41:VDD
p41:DOUT
p41:VSS
p41:DIN
p42:VDD
p42:DOUT
p42:VSS
p42:DIN
p43:VDD
p43:DOUT
p43:VSS
p43:DIN
p44:VDD
p44:DOUT
p44:VSS
p44:DIN
p45:VDD
p45:DOUT
p45:VSS
p45:DIN
p46:VDD
p46:DOUT
p46:VSS
p46:DIN
p47:VDD
p47:DOUT
p47:VSS
p47:DIN
p48:VDD
p48:DOUT
p48:VSS
p48:DIN
p49:VDD
p49:DOUT
p49:VSS
p49:DIN
p50:VDD
p50:DOUT
p50:VSS
p50:DIN
p51:VDD
p51:DOUT
p51:VSS
p51:DIN
p52:VDD
p52:DOUT
p52:VSS
p52:DIN
p53:VDD
p53:DOUT
p53:VSS
p53:DIN
p54:VDD
p54:DOUT
p54:VSS
p54:DIN
p55:VDD
p55:DOUT
p55:VSS
p55:DIN
p56:VDD
p56:DOUT
p56:VSS
p56:DIN
p57:VDD
p57:DOUT
p57:VSS
p57:DIN
p58:VDD
p58:DOUT
p58:VSS
p58:DIN
p59:VDD
p59:DOUT
p59:VSS
p59:DIN
p60:VDD
p60:DOUT
p60:VSS
p60:DIN
p61:VDD
p61:DOUT
p61:VSS
p61:DIN
p62:VDD
p62:DOUT
p62:VSS
p62:DIN
p63:VDD
p63:DOUT
p63:VSS
p63:DIN
p64:VDD
p64:DOUT
p64:VSS
p64:DIN
p65:VDD
p65:DOUT
p65:VSS
p65:DIN
p66:VDD
p66:DOUT
p66:VSS
p66:DIN
p67:VDD
p67:DOUT
p67:VSS
p67:DIN