#include <LiquidCrystal.h>

#define LED 7
#define PIR_SENSOR 5

#define JOY_HORZ A1
#define JOY_VERT A0
#define JOY_SEL 6


class Joystick
{
  public:
  Joystick(int pinHorz, int pinVert, int pinSel, LiquidCrystal *lcd)
  {
    _pinSel = pinSel;
    _pinVert = pinVert;
    _pinHorz = pinHorz;    
    _deadZone = 100;
    _selState = 0;
    _lcd = lcd;
    _delay = 2000;
    pinMode(_pinSel, INPUT);
    pinMode(_pinVert, INPUT);
    pinMode(_pinHorz, INPUT);
  }
  ~Joystick() = default;

  void start()
  {
    _delay = 2000;
    printDelay();
  }

  int getDelay()
  {
    return _delay;
  }

  void process()
  {
    int y = analogRead(_pinVert);
    int x = analogRead(_pinHorz);
    int push = debounce();
    
    if(x > 512 + _deadZone)//влево
    {
      decrementDelay();
      printDelay(); 
    }
    else if(x < 512 - _deadZone)//вправо
    {
      incrementDelay();
      printDelay();      
    }
    else if(y > 512 + _deadZone)//вверх
    {
      incrementDelay();
      printDelay();    
    }
    else if(y < 512 - _deadZone)//вниз
    {      
      decrementDelay();  
      printDelay();    
    }

    if(push != _selState)
    {     
      _delay = 2000;
      printDelay();
      _selState = push;
    } 
  }

  private:
  int _pinSel;  
  int _pinHorz;
  int _pinVert;  
  int _selState;  
  int _deadZone;
  
  LiquidCrystal *_lcd;
  int _delay;

  int debounce ()
  {
    int current = digitalRead(_pinSel);
    if(_selState != current)
    {
      delay(5);
      current = digitalRead(_pinSel);
    }
    return current;
  }

  void incrementDelay()
  {
    _delay += 1000;
    if(_delay > 10000)
    {
      _delay = 10000;
    }    
  };

  void decrementDelay()
  {
    _delay -= 1000;
    if(_delay < 2000)
    {
      _delay = 2000;
    }        
  }

  void printDelay()
  {
    _lcd->clear();
    _lcd->print("Delay: ");
    _lcd->print(_delay/1000);
    _lcd->print(" s");
  }
};

class Lamp
{
public:
  Lamp(int pin, int time)
  {
    pinMode(pin, OUTPUT);
    _pinLed = pin;
    _startTime = 0;
    _delay = time;
    _light = false;
  };

  ~Lamp() = default;

  bool isLighted()
  {
    return _light;
  }

  void setTimedLight(int time, unsigned long start)
  {
    _startTime = start;
    _delay = time;
    digitalWrite(_pinLed, HIGH);
    _light = true;
  }

  void timedLight()
  {
    if(_startTime + _delay <= millis())
    {
      digitalWrite(_pinLed, LOW);
      _light = false;
    }
  }
  private:
  int _pinLed;
  unsigned long _startTime;
  int _delay;
  bool _light;
};


LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
Joystick joystick(JOY_HORZ, JOY_VERT, JOY_SEL, &lcd);
Lamp lamp(LED, 2000);

void setup() 
{  
  pinMode(PIR_SENSOR, INPUT);  
  analogReference(DEFAULT);
  lcd.begin(16, 2, LCD_5x8DOTS);  
  joystick.start();
}

bool processed = false;

void loop() 
{
  unsigned long curLoopTime = millis();
  //обеспечение интервала опроса джойстика = 100 мс, чтобы не блокировать поток моргания светодиода через delay(100)
  if(curLoopTime % 100 > 90 && !processed)
  {
    joystick.process();
    processed = true;
  }
  else if(curLoopTime % 100 < 90)
  {
    processed = false;
  }  
  //если лампа не горит и сработал датчик стартуем свечение на заданное время начиная с екущего момента
  if(digitalRead(PIR_SENSOR) == HIGH && !lamp.isLighted())
  {
    lamp.setTimedLight(joystick.getDelay(), millis());    
  }
  if(lamp.isLighted())
  {
    lamp.timedLight();
  }   
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:VSS
lcd1:VDD
lcd1:V0
lcd1:RS
lcd1:RW
lcd1:E
lcd1:D0
lcd1:D1
lcd1:D2
lcd1:D3
lcd1:D4
lcd1:D5
lcd1:D6
lcd1:D7
lcd1:A
lcd1:K
r1:1
r1:2
r2:1
r2:2
led1:A
led1:C
joystick1:VCC
joystick1:VERT
joystick1:HORZ
joystick1:SEL
joystick1:GND
pir1:VCC
pir1:OUT
pir1:GND