New to programming, need some help with my program

I have created this code to control the turning off and on of my car headlights based on the sensor value of a photo cell. That part I got working, but what I want to do is once the headlights are on there needs to be 10 seconds of brightness before the headlights will turn off again in order to reduce flicker. I do want to do this without using delay as I will be expanding upon this code to do much more. Im having nothing but problems trying to get it to work using Millis, anyone have any ideas? Thanks

// initialize controllers and variables
int sensorPin = A0; // imput from photosensor
const int switchPin = 12; // imput from headlight combination switch, headlights + tail lights
const int autoswitchPin = 2; // imput from combination switch, now used for turning auto headlights on
int headlightController = 4; // output to headlight controller relay
int runninglightController = 5; // output to running light controller relay
int dashlightController = 6; // output to dash light controller relay
int autoswitchCutoff = 7; // this out put activates a normally closed relay circuit to act as a shutoff to the auto switch

// begin variables
int sensorValue = 0; // variable to store the value coming from the sensor
int switchValue = 0; // variable to store the value coming from the switch
int autoswitchValue = 0; // variable to store the value coming from the auto switch
unsigned long startTime; // the value returned from millis when the switch is pressed
int duration = 10000; // variable to store the duration
unsigned long previousMillis;

void setup() {

// initialize outputs
pinMode(headlightController, OUTPUT);
pinMode(runninglightController, OUTPUT);
pinMode(dashlightController, OUTPUT);
pinMode(autoswitchCutoff, OUTPUT);

// initialize inputs
pinMode(switchPin, INPUT);
pinMode(autoswitchPin, INPUT);
digitalWrite(2, HIGH);
Serial.begin(9600);
}

void loop(){

unsigned long currentMillis = millis(); // Grab snapshot of current time, this keeps all timing
// consistent, regardless of how much code is inside the next if-statement

unsigned long startTime = currentMillis - previousMillis;

// read the state of the switch value
switchValue = digitalRead(switchPin);

// read the state of the auto switch value
autoswitchValue = digitalRead(autoswitchPin);

// read the value from the photo sensor
sensorValue = analogRead(sensorPin);
Serial.print("Digital reading = ");
Serial.println(sensorValue); // serial monitor the raw analog reading of the sensor

// manual lighting mode

if (switchValue == LOW)
digitalWrite(autoswitchCutoff, HIGH);
else {
digitalWrite(autoswitchCutoff, LOW);
}
if (switchValue == LOW)
digitalWrite(headlightController, HIGH);
else {
digitalWrite(headlightController, LOW);
}
if (switchValue == LOW)
digitalWrite(runninglightController, HIGH);
else {
digitalWrite(runninglightController, LOW);
}
if (switchValue == LOW)
digitalWrite(dashlightController, HIGH);
else {
digitalWrite(dashlightController, LOW);
}

// auto lighting section
if((autoswitchValue == LOW) && (sensorValue < 410)) {
digitalWrite(headlightController, HIGH);
previousMillis = currentMillis;
}
while((sensorValue > 410) && ( startTime = 10000)) {
digitalWrite(headlightController, LOW);
}
}

sheananigans:
That part I got working, but what I want to do is once the headlights are on there needs to be 10 seconds of brightness before the headlights will turn off again in order to reduce flicker.

I think you may want to set a dead zone to create hysteresis...

if (sensorValue < 470)
{
  lightsOn();
}
else if (sensorValue > 500)
{
  lightsOff();
}

Once the headlights are switched on, pinpoint that time.
You can use previousMillis, but I prefer a new global variable: unsigned long headlightMillis;
You need also an extra global flag, that indicates that the headlights are on: boolean headlightOn = false;

Do not use startTime, you can use currentMillis.
Remove the 'while' at the end of the loop() function.

When the headlights are turned on:

  digitalWrite(headlightController, HIGH);
  headlightMillis = currentMillis;
  headlightOn = true;

At the begin of loop, check if the conditions have met.

void loop(){
  unsigned long currentMillis = millis();      // Grab snapshot of current time, this keeps all timing
                                               // consistent, regardless of how much code is inside the next if-statement
                                               
  // check the headlights
  if( headlightOn ) {
    // Let's test if enough time has passed.
    if (currentMillis - headlightMillis > duration) {
      // turn headlights off.
      digitalWrite(headlightController, LOW);
      headlightOn = false;
    }
  }

setting a sensor deadzone is my backup plan if I cant get this to work...
So I made the modifications to the code, unfortunately the headlights turn on instantly with darkness and off instantly with light.
The way I want it to work is in darkness they turn on right away and once enough light hits the sensor to turn the headlights off, then wait ten seconds, turn the headlights off.

// initialize controllers and variables
int sensorPin = A0;             // imput from photosensor
const int switchPin = 12;       // imput from headlight combination switch, headlights + tail lights
const int autoswitchPin = 2;    // imput from combination switch, now used for turning auto headlights on
int headlightController = 4;    // output to headlight controller relay
int runninglightController = 5; // output to running light controller relay
int dashlightController = 6;   // output to dash light controller relay
int autoswitchCutoff = 7;       // this out put activates a normally closed relay circuit to act as a shutoff to the auto switch

// begin variables
int sensorValue = 0;            // variable to store the value coming from the sensor
int switchValue = 0;            // variable to store the value coming from the switch
int autoswitchValue = 0;        // variable to store the value coming from the auto switch
boolean headlightOn = false;
unsigned long headlightMillis;


void setup() {
  
// initialize outputs
  pinMode(headlightController, OUTPUT); 
  pinMode(runninglightController, OUTPUT); 
  pinMode(dashlightController, OUTPUT);  
  pinMode(autoswitchCutoff, OUTPUT);
  
// initialize inputs
  pinMode(switchPin, INPUT);   
  pinMode(autoswitchPin, INPUT);  
  digitalWrite(2, HIGH);
  Serial.begin(9600);    
}

void loop(){
  
  
  unsigned long currentMillis = millis();      // Grab snapshot of current time, this keeps all timing
                                               // consistent, regardless of how much code is inside the next if-statement
                                               
  int duration = 10000; 

// read the state of the switch value
  switchValue = digitalRead(switchPin);
  
// read the state of the auto switch value
  autoswitchValue = digitalRead(autoswitchPin);
  
// read the value from the photo sensor
  sensorValue = analogRead(sensorPin);    
  Serial.print("Digital reading = ");
  Serial.println(sensorValue);                  // serial monitor the raw analog reading of the sensor
  
// manual lighting mode

   if (switchValue == LOW)
    digitalWrite(autoswitchCutoff, HIGH);
     else {
      digitalWrite(autoswitchCutoff, LOW);
     }
   if (switchValue == LOW)
    digitalWrite(headlightController, HIGH);
     else {
      digitalWrite(headlightController, LOW);
     }
   if (switchValue == LOW)
    digitalWrite(runninglightController, HIGH);
     else {
      digitalWrite(runninglightController, LOW);
    }
   if (switchValue == LOW)
    digitalWrite(dashlightController, HIGH);
     else {
      digitalWrite(dashlightController, LOW);
    }

// auto lighting section
if((autoswitchValue == LOW) && (sensorValue < 410)) {
  digitalWrite(headlightController, HIGH);
  headlightMillis = currentMillis;
  headlightOn = true;
}
 // check the headlights
  if( headlightOn == true ) {
    // Let's test if enough time has passed.
    if (currentMillis - headlightMillis > duration) {
      // turn headlights off.
      digitalWrite(headlightController, LOW);
      headlightOn = false;
}
}
}
[code/]

I think my code snippet is working, but you use also the variable 'switchValue' to turn the headlights on and off.

Can you write once more what it should do ?

It is getting dark: turn headlights on.
It is getting light: wait 10 seconds, turn headlights off.
Where does this switch come in ?
What should happen if it is suddenly dark and the delay of 10 seconds is busy ?

At this moment, the delay is started as soon as the lights are turned on. You have to change that to make the delay start only after it is light enough and the headlights are on.
That means another flag: boolean delayOn = false;
So you have a flag for the lights on, and a flag that the delay is going on.

You can also use a variable for the state. For example a value of '0' means headlights are off; a value of '1' means headlights are on; a value of '2' means headslights on and delay 10 seconds is going on.

Let me try to explain fully what the entire code will do. There are two inputs from switches. One is to manually turn on the headlights indecently of the sensor value, the other sets the headlights on auto so that when it is dark the headlights come on right away, then if it were to suddenly get bright say from passing under a streetlight , wait ten seconds to turn the headlights off. But say its bright for less than ten seconds, then the headlights will stay on.

Peter_n:
I think my code snippet is working, but you use also the variable 'switchValue' to turn the headlights on and off.

Can you write once more what it should do ?

It is getting dark: turn headlights on.
It is getting light: wait 10 seconds, turn headlights off.
Where does this switch come in ?
What should happen if it is suddenly dark and the delay of 10 seconds is busy ?

At this moment, the delay is started as soon as the lights are turned on. You have to change that to make the delay start only after it is light enough and the headlights are on.
That means another flag: boolean delayOn = false;
So you have a flag for the lights on, and a flag that the delay is going on.

You can also use a variable for the state. For example a value of '0' means headlights are off; a value of '1' means headlights are on; a value of '2' means headslights on and delay 10 seconds is going on.

:slight_smile:

Does the manual switch only override when turning it on ? or should it also turn it off when it has been turned on automatically ? If not, you can never turn the lights off with the manual switch in the dark. When the manual switch should always be able to turn the light on and off, you need a motorized switch or a switch with a middle position for 'automatic'.

The delay is not just an delay, you want to measure the light during the delay. Do you want to measure the average light or darkest moments ?
For an average it is possible to have a running average of the last 10 seconds.
For the darkest moment, you just can stop the calculation of the delay when it gets darker. The delay will start as soon as it is light again.

gave it some thought.... take a look at this and let me know what you think:

compiled but untested...

#define LIGHTS_ON 1
#define LIGHTS_OFF 0

// initialize controllers and variables
const int sensorPin = A0;             // imput from photosensor
const int switchPin = 12;       // imput from headlight combination switch, headlights + tail lights
const int autoswitchPin = 2;    // imput from combination switch, now used for turning auto headlights on
const int headlightController = 4;    // output to headlight controller relay
const int runninglightController = 5; // output to running light controller relay
const int dashlightController = 6;   // output to dash light controller relay
const int autoswitchCutoff = 7;       // this out put activates a normally closed relay circuit to act as a shutoff to the auto switch
int oldState;
// begin variables
int sensorValue;            // variable to store the value coming from the sensor
int switchValue;            // variable to store the value coming from the switch
int autoswitchValue;        // variable to store the value coming from the auto switch
boolean headlightOn = false;
unsigned long headlightMillis;
boolean myTimer;
//
void setup() 
{
  Serial.begin(9600);    
  pinMode(headlightController, OUTPUT); 
  pinMode(runninglightController, OUTPUT); 
  pinMode(dashlightController, OUTPUT);  
  pinMode(autoswitchCutoff, OUTPUT);
  pinMode(switchPin, INPUT);   
  pinMode(autoswitchPin, INPUT);  
  digitalWrite(autoswitchPin, HIGH);
}
//
void loop()
{
  unsigned long currentMillis = millis();      // Grab snapshot of current time, this keeps all timing                                         
  int state = digitalRead(switchPin)? LIGHTS_ON : LIGHTS_OFF;

  if (state == LIGHTS_ON)
  {
    headLightsOperate();
    if (oldState == LIGHTS_OFF)
    {
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  else 
  {
    if (oldState == LIGHTS_ON)
    {
      headLightsOff();
      digitalWrite(autoswitchCutoff, LOW);
      digitalWrite(headlightController, LOW);
      digitalWrite(runninglightController, LOW);
      digitalWrite(dashlightController, LOW);
    }
  }
  oldState = state;
}
void headLightsOperate()  //controls headlights based on light sensor and timer...
{
  autoswitchValue = digitalRead(autoswitchPin);
  sensorValue = analogRead(sensorPin);  
  Serial.print("Digital reading = ");
  Serial.println(sensorValue);                  // serial monitor the raw analog reading of the sensor

  if((autoswitchValue == LOW) && (sensorValue < 410) && myTimer == true) 
  {
    digitalWrite(headlightController, HIGH);
    headlightOn = true;
    headlightMillis = millis();
  }
  else if((autoswitchValue == LOW) && (sensorValue > 450) && myTimer == true) 
  {
    digitalWrite(headlightController, LOW);
    headlightOn = false;
    headlightMillis = millis();
  }
  myTimer = (millis() - headlightMillis >= 10000UL) ? true : false;
}

void headLightsOff()
{
  digitalWrite(headlightController, LOW);
}

I'm sorry, but I can't tell what the sketch would do. It is not straightforward enough. I think it will not work. When the manual switch is off, the automatic part is not running ?

You really have to know what to do, before writing code. You want to write code, but that is not the target. The target is to have code that you still understand when you look at it in a few years.

I prefer to have the automatic part running all the time, even when the lights are manually on. That means that when the lights are manually switched off, the automatic part could be busy with the delay, and that might turn the lights off after 3 seconds.

I tried the code you supplied BulldogLowell, it didn't work... thank you though I really appreciate it.

Let me try to explain what the sketch will do a little further.

The switch is a three way combination switch in the form of a knob. When the switch is in the off position auto headlight control and manual control should be OFF.

When the knob is rotated one click forward to the AUTO setting, power will pass to the arduino pin.

When the knob is rotated another click forward to the MANUAL setting, power is at that point passing to both output pins which is why I run the wire for the auto setting through a relay so that when you turn the headlights to MANUAL it discontinues any code that has to do with AUTO by killing power to the arduino pin from the AUTO portion of the switch via the relay.

When the headlights are set to AUTO they will need to turn on in darkness and when light hits the sensor it needs to delay for x amount of time before turning the headlights back off again. I want it to function this way so that when I drive under street lights the headlights wont turn off, as the amount of time that the light hits the sensor would then be too short to turn the headlights off.

I hope this makes sense, like I said I am fairly new to coding and so far I completely understand my code as I have it. Im just having difficulty getting that delay in there.

I think the original code snippet you gave me might work, but I need the code to grab the time since sensorValue > 410, not the time since the headlights are on.

Thank you for all your help.

Peter_n:
I'm sorry, but I can't tell what the sketch would do. It is not straightforward enough. I think it will not work. When the manual switch is off, the automatic part is not running ?

You really have to know what to do, before writing code. You want to write code, but that is not the target. The target is to have code that you still understand when you look at it in a few years.

I prefer to have the automatic part running all the time, even when the lights are manually on. That means that when the lights are manually switched off, the automatic part could be busy with the delay, and that might turn the lights off after 3 seconds.

I tried the code you supplied BulldogLowell, it didn't work...

Nonsense. It did something. You didn't explain what it actually did.

Thank you for your completely unhelpful comment. I never said it did nothing. What I said is that it didn't work. What it did was turn the headlights on when the auto switch was turned on, but what it didn't do was turn the headlights off again when the sensor value was greater than 410.

PaulS:

I tried the code you supplied BulldogLowell, it didn't work...

Nonsense. It did something. You didn't explain what it actually did.

so please take a look at this, for now pseudo code... is this the behaviour you want? the three states and the actions?

we will then work on the "auto" function for the headlights and the logic from the three position switch. My instinct says you have an extra input but take a look at this:

void loop()
{
  //
  // Here we need to put in the logic to decide what state to pur your arduino into
  //this next line is a place holder:
  int state = LIGHTS_OFF;
  //
  //
  
  if (state == LIGHTS_OFF)
  {
    headLightsOff();
    digitalWrite(autoswitchCutoff, LOW);
    digitalWrite(headlightController, LOW);
    digitalWrite(runninglightController, LOW);
    digitalWrite(dashlightController, LOW);
  }
  else if (state == MANUAL_MODE) // turn ON all the lights including Headlight
  {
    if (oldState == LIGHTS_OFF || oldState == AUTO_MODE)
    {
      digitalWrite(headlightController, HIGH);
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  else if (state == AUTO_MODE)  // turn ON all the lights EXCLUDING Headlight, which will operate according to the timer/sensor
  {
    headLightsOperate();
    if (oldState == LIGHTS_OFF || oldState == MANUAL_MODE)
    {
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  oldState = state;
}

What I said is that it didn't work.

"It didn't work" and "It didn't do what I wanted" are two completely different things. "It did this, but I wanted that" gives us something to go on. "It didn't work" is just whining.

I was neither complaining nor whining.
If you wanted to know what it did then all you had to do was ask.

PaulS:

What I said is that it didn't work.

"It didn't work" and "It didn't do what I wanted" are two completely different things. "It did this, but I wanted that" gives us something to go on. "It didn't work" is just whining.

This looks to be on the right track! I will work through this when I get off work today and see if I can add in the lines necessary to make it function as I need. Thank you for all your help, I really appreciate it. The only inputs I have are from the auto switch, the manual switch, and from the photocell.

BulldogLowell:
so please take a look at this, for now pseudo code... is this the behaviour you want? the three states and the actions?

we will then work on the "auto" function for the headlights and the logic from the three position switch. My instinct says you have an extra input but take a look at this:

void loop()

{
  //
  // Here we need to put in the logic to decide what state to pur your arduino into
  //this next line is a place holder:
  int state = LIGHTS_OFF;
  //
  //
 
  if (state == LIGHTS_OFF)
  {
    headLightsOff();
    digitalWrite(autoswitchCutoff, LOW);
    digitalWrite(headlightController, LOW);
    digitalWrite(runninglightController, LOW);
    digitalWrite(dashlightController, LOW);
  }
  else if (state == MANUAL_MODE) // turn ON all the lights including Headlight
  {
    if (oldState == LIGHTS_OFF || oldState == AUTO_MODE)
    {
      digitalWrite(headlightController, HIGH);
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  else if (state == AUTO_MODE)  // turn ON all the lights EXCLUDING Headlight, which will operate according to the timer/sensor
  {
    headLightsOperate();
    if (oldState == LIGHTS_OFF || oldState == MANUAL_MODE)
    {
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  oldState = state;
}

OK

the whole sketch, where it stands:

#define LIGHTS_OFF 0
#define MANUAL_MODE 1
#define AUTO_MODE 2


// initialize controllers and variables
const int sensorPin = A0;             // imput from photosensor
const int switchPin = 12;       // imput from headlight combination switch, headlights + tail lights
const int autoswitchPin = 2;    // imput from combination switch, now used for turning auto headlights on
const int headlightController = 4;    // output to headlight controller relay
const int runninglightController = 5; // output to running light controller relay
const int dashlightController = 6;   // output to dash light controller relay
const int autoswitchCutoff = 7;       // this out put activates a normally closed relay circuit to act as a shutoff to the auto switch
int oldState;
// begin variables
int sensorValue;            // variable to store the value coming from the sensor
int switchValue;            // variable to store the value coming from the switch
int autoswitchValue;        // variable to store the value coming from the auto switch
boolean headlightOn = false;
unsigned long headlightMillis;
boolean myTimer;
//
void setup() 
{
  Serial.begin(9600);    
  pinMode(headlightController, OUTPUT); 
  pinMode(runninglightController, OUTPUT); 
  pinMode(dashlightController, OUTPUT);  
  pinMode(autoswitchCutoff, OUTPUT);
  pinMode(switchPin, INPUT);   
  pinMode(autoswitchPin, INPUT);  
  digitalWrite(autoswitchPin, HIGH);
}
//
void loop()
{
  //
  // Here we need to put in the logic to decide what state to pur your arduino into
  //this next line is a place holder:
  int state = LIGHTS_OFF;
  //
  //
  
  if (state == LIGHTS_OFF)
  {
    headLightsOff();
    digitalWrite(autoswitchCutoff, LOW);
    digitalWrite(headlightController, LOW);
    digitalWrite(runninglightController, LOW);
    digitalWrite(dashlightController, LOW);
  }
  else if (state == MANUAL_MODE) // turn ON all the lights including Headlight
  {
    if (oldState == LIGHTS_OFF || oldState == AUTO_MODE)
    {
      digitalWrite(headlightController, HIGH);
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  else if (state == AUTO_MODE)  // turn ON all the lights EXCLUDING Headlight, which will operate according to the timer/sensor
  {
    headLightsOperate();
    if (oldState == LIGHTS_OFF || oldState == MANUAL_MODE)
    {
      digitalWrite(autoswitchCutoff, HIGH);
      digitalWrite(headlightController, HIGH);
      digitalWrite(runninglightController, HIGH);
      digitalWrite(dashlightController, HIGH);
    }
  }
  oldState = state;
}
void headLightsOperate()  //controls headlights based on light sensor and timer...
{
  autoswitchValue = digitalRead(autoswitchPin);
  sensorValue = analogRead(sensorPin);  
  Serial.print("Digital reading = ");
  Serial.println(sensorValue);                  // serial monitor the raw analog reading of the sensor

  if((autoswitchValue == LOW) && (sensorValue < 410) && myTimer == true) 
  {
    digitalWrite(headlightController, HIGH);
    headlightOn = true;
    headlightMillis = millis();
  }
  else if((autoswitchValue == LOW) && (sensorValue > 450) && myTimer == true) 
  {
    digitalWrite(headlightController, LOW);
    headlightOn = false;
    headlightMillis = millis();
  }
  myTimer = (millis() - headlightMillis >= 10000UL) ? true : false;
}

void headLightsOff()
{
  digitalWrite(headlightController, LOW);
}

If you wanted to know what it did then all you had to do was ask.

We shouldn't have to. You have the code. You have the hardware. You observed the actions of the code on the hardware. You are the one with the obligation of being our eyes and ears if you want help.

I agree with PaulS. It isn't helpful to say things "work" or "don't work". It helps to describe what happens. For example "the lights come on but don't go off" or "the lights don't come on at all" or "the lights stay on for 5 seconds but I expected 10 seconds".

That gives people something concrete to look for. In particular you should state what you expected, and what actually happened.

   if (switchValue == LOW)
    digitalWrite(autoswitchCutoff, HIGH);
     else {
      digitalWrite(autoswitchCutoff, LOW);
     }
   if (switchValue == LOW)
    digitalWrite(headlightController, HIGH);
     else {
      digitalWrite(headlightController, LOW);
     }
   if (switchValue == LOW)
    digitalWrite(runninglightController, HIGH);
     else {
      digitalWrite(runninglightController, LOW);
    }
   if (switchValue == LOW)
    digitalWrite(dashlightController, HIGH);
     else {
      digitalWrite(dashlightController, LOW);
    }

Why are you doing this? If switchValue is LOW do something. And then see if switchValue is LOW again. Four times. That is just confusing and obscure.

Like I said I am very new to coding of any kind. I am not here to argue with anyone, I just want to solve this problem. My apologies for not providing the information that you wanted. I originally combined all of those actions into one if then statement but for some reason the headlights would not turn on. Separating them out seemed to fix it.

So with the code as it is that BulldogLowell modified I am trying to go through it piece by piece to make sure I understand every part of it before I try to add or modify anything. The code as it was given currently does nothing, the headlights don't turn on in either auto or manual mode. I think I understand that I need to add in the section that controls what state the boolean flags are in.

Is that correct?

sort of...

we are identifying how many unique states you need (OFF, MANUAL, AUTO) and then create the mechanism for changing the state...

(which is a lot of what programming is, BTW)

now... you ar happy with the state... so what makes them change... in plain english works!