Room lighting with nano, pwm, relays, photo diodes

Hey guys, sry for being away such a long time. Thanks for your advice, I wont to giv esome feedback:

An aditional remote was a nogo for me. We hat remotes. And yes, we need more than one light setting.

I got it to work, but I can't update my rduino anymore, because I destroyed my USB-TTL Adapter...

I want to post my code, its still not tested.

In the future, I want to integrate an XBee connection to controll the light via an self build remote conroll, which also controlls the home cinema.

#include <Bounce2.h>      // See https://github.com/thomasfredericks/Bounce2/wiki
#include <EEPROM.h>


const int programs = 5;                      // Number of light programs
const int eeprom_start = 10;                 // First adress for EEPROM access. Max 1023 minus programs * 3
const unsigned long time_debounce = 100;     // time needed for debounce the push button
const unsigned long time_setup = 5000;       // time needed for press push button to enter setup-mode

/*
 * Just some variables for manipulating the delay between
 * two brightness steps in setup-mode
 */
const int delay_faktor = 10;                 // delay_faktor * (delay_minuend - i / delay_divisor)
const int delay_minuend = 50;                //
const float delay_divisor = 2.0;             //

/*
 * Pin-Configuration:
 * Important to use pin 3 and 11. In setup, the neccessary CPU registers
 * for phase correct PWM were set for these 2 pins. For details: https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
 * 
 */

const int input = 12;               // Input from the optocoupler 
const int SpotRelaisPin = 8;        // Controll output to 230V AC relay for turning LED spots on/off
const int transformer = 7;          // Controll output to 230V AC relay for turning LED-stripe transformer on/off
const int LEDchannel1 = 3;          // First channel of LED stripe
const int LEDchannel2 = 11;         // Second channel of LED stripe


/* byte LED[(programs) * 3];
 * Array that contains the brightness-values for all LED at all program states
 * 
 * Structure:
 * Program  |  LED channel 1  | LED channel 2 | LED Spots
 *    0     |          0               1             2
 *    1     |          3               4             5
 *    2     |          6               7             8
 *    n     |       (3 * n)       (3 * n + 1)   (3 * n + 2)
 *            Values in table-content above represent the index of the array.
 */
byte LED[(programs) * 3];       

byte program = 0;               // counter for active light program

unsigned long time_pushed = 0;         // Point of time, when push button was closed last time
unsigned long time_released = 0;       // Point of time, whan push button was opened last time


/* const unsigned long max_long = ~((unsigned long)0);
 *  
 * stores the highest possible value of millis() before it overflows.
 * Max value is 2^32 -1 bit (4,294,967,295). 
 * See https://www.arduino.cc/reference/en/language/functions/time/millis/
 * 
 * This constant is used to check variables for reching the limit of
 * unsigned long and start routines that prevent logic errors.
 * 
 */
const unsigned long max_long = ~((unsigned long)0);

Bounce deb_input = Bounce();
 

void setup()
{
  deb_input.interval(time_debounce);
  pinMode(input, INPUT);                            //-------------
  pinMode(SpotRelaisPin, OUTPUT);
  pinMode(transformer, OUTPUT);                     // Set all needed Pins to In or out
  pinMode(LEDchannel1, OUTPUT);
  pinMode(LEDchannel2, OUTPUT);                     //-------------
  deb_input.attach(input);
  

/*
 * The following two lines will preset the registers in Atmega 328 to 
 * phase correct PWM at pins 3 and 11.
 * 
 * Just modifying OCR2A (0-255) will configure pin 3
 * Just modifying OCR2B (0-255) will configure pin 11
 * 
 * For details: https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
 * 
 */
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);  // Initialising of phase correct PWM
  TCCR2B = _BV(CS22);                               // for pins 3 and 11
  
  digitalWrite(transformer, HIGH);                  // Make sure that both channels to the relay are HIGH
  digitalWrite(SpotRelaisPin, HIGH);                // The relay will switch, if the output is LOW
  for(int i = 0; i < (programs * 3); i++)           // Read the full program from the EEPROM. This prevents from 
    LED[i] = EEPROM.read(eeprom_start + i);         // loosing configuration bye power loss (e.g. blackput)
}

/* blink_sequenz
 *  int n - number of iterations
 *  
 *  Just blink that often, which LED you are going to program:
 *  1, 2 or 3.
 *  
 */
void blink_sequenz(int n)
{
  for (int i = 0; i < n; i++)
  {
    if (i != 0) delay(1500);
    LED[(program * 3) + 0] = 255;
    LED[(program * 3) + 1] = 255;
    LED[(program * 3) + 2] = 1;
    set_led();
    delay(1500);
    LED[(program * 3) + 0] = 0;
    LED[(program * 3) + 1] = 0;
    LED[(program * 3) + 2] = 0;
    set_led();
    if (i == n) delay(1500);
  }    
}

/*
 * save_program
 * 
 * Stores the LED brightnesses of actual program to the EEPROM
 * via EEPROM.uptdate
 * 
 */
void save_program()
{
  for(int i = program * 3; i < program * 3 + 3; i++)
    EEPROM.update(eeprom_start + i, LED[i]);
}


/*
 * set_led();
 * 
 * The function wich set all the outputs and manipulates the CPU-PWM registers.
 * 
 * It reads the actual program and actual brightnes values from
 * LED[program+[1,2,3]]
 * 
 */
void set_led()
{
  if(program == 0){
    digitalWrite(SpotRelaisPin, HIGH);
    digitalWrite(transformer, HIGH);
    return ;
  }
  if(LED[(program * 3) + 2] > 0)
    digitalWrite(SpotRelaisPin, LOW);
      else
    digitalWrite(SpotRelaisPin, HIGH);

  if(LED[(program * 3) + 0] > 0 || LED[(program * 3) + 1] > 0)
    digitalWrite(transformer, LOW);
  else
    digitalWrite(transformer, HIGH);

  OCR2A = LED[(program * 3) + 0];
  OCR2B = LED[(program * 3) + 1];

}


/*
 * int inputdelay(unsigned long wait)
 * 
 * Waitung for wait milliseconds for any input
 * 
 * If an input is recognized, the function aborts with return 1 
 * before teh tim eis over.
 * 
 * If no input occurs during waitung time, function returns 0.
 * 
 */
int inputdelay(unsigned long wait)
{
  unsigned long now = millis();
  /*
   * This if is to prevent logical errors if millis() almost overflows.
   * It just delays the execution of the sketch to wait for the overflow 
   * before continue the sketch
   */
  if(max_long - wait < now)
  {
    delay(wait + 2);
    now = millis();
  }
  
  while(now + wait <= millis())
  {
    deb_input.update();
    if (deb_input.rose()) 
    {
      while(!deb_input.fell())
      {
        delay(5);
        deb_input.update();
      }
      return 1;
    }
  }
  return 0;
}


/*
 * int pwm_setup(int set_temp)
 * 
 * This function just increase (0 to 250) and decrease (250 - 0) 
 * the brightness of one LED-stripe and wait for an acknowledge (input) of some brightness 
 * via inputdelay().
 * 
 * It runs infinite till some input is recognized via inputdelay() and returns always 1.
 * 
 */
int pwm_setup(int set_temp)
{
  while(1)
  {
    for (int i = 0; i < 26; i++) 
    {
      LED[(program*3)+set_temp] = i * 10;
      set_led();
     if(inputdelay(delay_faktor * (delay_minuend - i / delay_divisor)))
       return 1;
    }
  
    for (int i = 25; i == 0; i--) 
    {
     LED[(program*3)+set_temp] = i * 10;
     set_led();
     if(inputdelay(delay_faktor * (delay_minuend - i / delay_divisor)))
       return 1;
    }
  }
}


/*
 * void setup_led()
 * 
 * This function manages the call of other functions in order to
 * change the actual LED program.
 * 
 */
void setup_led()
{
  int set = 0;

  while(set < 2)
  {
    blink_sequenz(set+1);
    set += pwm_setup(set);
  }
  
  blink_sequenz(set+1);
  while(set < 3)
  {
    LED[(program*3)+set] = !LED[(program*3)+set];
    set_led();
    if(inputdelay(1500)) 
      set++;
  }
  save_program();
}


/*
 * void loop()
 * 
 * Main function of all arduino sketches.
 * It checks the input continuously and increasy program counter by 1 if
 * Push button is pushed, released and waited for end of debounce time.
 * 
 * If button is pushed and hold for time_setup milliseconds, setup_led() will
 * edit the actual program.
 */
void loop()
{
  int change;
  if(max_long - (time_setup + 500) <= millis())
    delay(time_setup + 1000);  
 
  change = deb_input.update();
  
  if (deb_input.rose())
    time_pushed = millis();

  if (deb_input.fell()) 
  {
    if(program < programs - 1)
      program++;
    else
      program = 0;

    set_led();
  }

  if (millis() - time_pushed >= time_setup && !change)
    setup_led();
}

My wife loves the new lamp :slight_smile: