Turnin on light in room with photoresistor

Hello all!

I wanted to briefly share my project with community and ask about hints, how can it be corrected - for sure i made a lot of bugs :melting_face: - I want to treat this topic as project guideline.

Project goal: Turning on light in room with NodeMCU v.3, relay module and photoresistor.
Project limitation: I need to use relay module - i have in my room only ordinary light bulb without any LED light.
Project description: Takes 20 samples from photoresistor with 1s delay between readout, calculate avarage light intesitifi - base on that NodeMCU decide to turn ON or OFF realy connected to light bulb
Main question regarding project:

  • 1s delay function causes "lags" in Arduino IoT cloud connection and updating data, is it any solution to correct this behavior? i think it's related to "Update" function, i do not think that I implemented it correctly.
  • A lot of lags is also visible in MS Edge browser - data is not updated correctly - sometimes is ok for 5 min, then big lag for next 5 min, and after that everithing back to normal. In android application for Arduino IoT Cloud it is not visible at all, everything update correctly.

Attaching project below:
Light_sensor.zip (6,2 KB)

Many thanks for any hints how to correct or upgrade project.

Best regards
Eldiane.

Your topic was MOVED to its current forum category as it is more suitable than the original

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the </> icon above the compose window) to make it easier to read and copy for examination

1 Like

it's not 1s it's 20 times 1s delay ==> 20s before you return to the main loop...

You need to learn how to use millis(). Look at Using millis() for timing. A beginners guide and Several things at the same time

1 Like

Thanks a lot for link @J-M-L! I will read information and correct my project.

also why do you pass pointers around when your data is in a global variable?

you could use a simple technique to keep a moving average by taking 90% (say) of the previous photoresistor value and 10% of the new one (adjust the 90/10 to react more quickly or slowly to changes) this way you would not need the array and the delays

I changed for loop to add youre technique,

  float previous_value_ratio = 0.9;
  float new_value_ratio = 0.1;

  for(int *p = &dataTable[1]; p <= &dataTable[19]; p++)
  {
    avaLightValue += (*(p-1))*previous_value_ratio+(*p)*new_value_ratio;
  }

Also I added millis() function to the code, but to be honest maybe i will get rid of it and implement solution wihout any delay.

Youre right that i am messing with pointer when array is declared as global variable - it should not be in that way. I moved array declaration from "sensorVariables.h" to collectDataFromSensor function

int * collectDataFromSensor()
{
  currentMillis = millis();
  int dataTable[20];
  
  if(currentMillis - startMillis >= period)
  {
    for(int i = 0; i<20; i++)
    {
      lightSensor = analogRead(analogPin);
      dataTable[i] = lightSensor;
      Serial.println(String("Table value[") + i + String("]: ") + dataTable[i]);
    }
  }
  startMillis = currentMillis;
  
  return dataTable;
}

also last one point, i was wondering what will happen when avarage light intensity will be "jumping" below and above treshold. I quickly made a little diagram which should clearly show the situation.

The relay will be toggling and my lamp will be blinking till the average light intesity stabilaze below or above treshold, how avoid such a situation? use millis() in proper way? - To be honest i do not read this tread carfully yet - but for sure i will do it - Implemented only "basic" situation", as i said before it will be great to avoid any delay. Or do you have different idea?

Corrected code can be found here:
Light_sensor.zip (6,7 KB)

you still have the array. The idea is to get rid of the array

const byte sensorPin = A0;
const float previous_value_ratio = 0.9;
const float new_value_ratio = 1.0 - previous_value_ratio;

float sensorValue;

void setup() {
  Serial.begin(115200);
  sensorValue = analogRead(sensorPin);
}

void loop() {
  sensorValue = previous_value_ratio * sensorValue + new_value_ratio * analogRead(sensorPin);
  ...
}
1 Like

Read up on hysteresis and don't use the same threshold value to turn the relay on as you do to turn it off

1 Like

Right now i get youre point of view. I deleted all unnecessary code, and use youre solution - Works perfectly! :heart_eyes: Thanks @J-M-L ! I added from my side function - in future i want to expand NodeMCU with LED strip control - so i think it will be better to "sort" everything in corresponding functions.

Right now i will play little bit to set best previous/new sensor value ratio :wink:

Light_sensor.zip (5,8 KB)

OFC i will read about millis function, seems to be really great topic for nub like me. :wink:

always good to study!
have fun

hello @UKHeliBob definitely i will read about it - I will came back with code upgrade :wink: Right now it seems that the same treshold for turn ON/OFF relay is ok - but i will test it deeper

the challenge is when the value you get is right at the treshold. at every read (because of possible very small variations) you'll go above and below the treshold and you'll get bad blinking.

using an hysteresis will take care of this

So definitely i need to know how to implement it, blinking is the main issue here. I will come back with solution/question :wink:

Hi, @eldiane
Please post your code on your post, not in zip file.

To add code please click this link;

Can you also please post a schematic of your project?
Why do you need to sample every 1ms?

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:
PS, your graph in post one is not the response you will get from the LDR.
What is you mains frequency?

Hi,
Your graph shows what the current through the lamp will be, but out of the LDR it will be the equivalent of rectified AC.

Even though the current changes direction in the lamp, the photon output will not change direction, light intensity will not.
If you have 50Hz mains, AC period is 20ms, do you will have a pulsed output of 10ms from the LDR.

Tom... :grinning: :+1: :coffee: :australia:

hello @TomGeorge,

Can you also please post a schematic of your project?

i do not have a perfect schematic but i made someting in https://www.circuito.io - please do not be scared :smiley:


Later i will create something in Eagle, i do not find on https://www.circuito.io/ the correct relay module, my it's "1 relay module high/low level trigger". Also i cannot find any lamp to connect so i left relay unplugged.
image

Why do you need to sample every 1ms?

It is not necessary - right now i do not use any delay in the program, is it something bad? In youre opinion will be better to collect data with delay?

What is you mains frequency?

Are you asking about min/max output from LDR?

So if my ADC is 50 Hz and 20 ms period need to be applied, maybe it is good idea to use millis function with 20 ms - there is no point to update sensor data "so fast".

hello @J-M-L

I created something like this:

void toggleRelayBasedOnValueFromSensor(float sensorValue){
  int treshold = 750;
  int tresholdMargin = 20;
  
  if(sensorValue >= (treshold + tresholdMargin)){
    digitalWrite(relayPin, LOW);
  }
  else if(sensorValue <= (treshold - tresholdMargin)){
    digitalWrite(relayPin, HIGH);
  }
}

I tested it this morning at sunrise - the relay switches off without any problems after activating the threshold - without any "blink". I will left it till sunset and check if relay will turn on.

Edit: I need to add web page which I based on, maybe someone will also need help with similar problem, Implementation of a Measurement Hysteresis on Arduino • AranaCorp

That’s good !

This way you have some sort of security interval where you don’t change the state of the system

Well done !

1 Like

I have one more point regarding correct program working. Yesterday i saw really strange behavior, my NodeMCU works all the time correctly, but when i woke up today morning i saw that connection to my network was interrupted - I was seeing it before few times (my network is set correctly, all other connected devices works correctly - network was up and running for 100%) - After that connection was not restored (I got message in serial monitor "Connection to failed, retried in 500ms"). But when i put into code one line with Serial.println function problem do not occur. I do not know if it's really depends on Serial.print function.

Here is the code without Serial. println function

/* 
  Sketch generated by the Arduino IoT Cloud Thing "Untitled"
  https://create.arduino.cc/cloud/things/992e25a6-d4ba-4196-b4e3-75b4b99ee50b 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  float sensorValue;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
#include "sensorVariables.h"

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  pinMode(relayPin, OUTPUT);
  sensorValue = analogRead(analogPin);
}

void loop() {
  sensorValue = getSensorValue(sensorValue);
  toggleRelayBasedOnValueFromSensor(sensorValue);
  ArduinoCloud.update();
}

float getSensorValue(float sensorValue)
{
  sensorValue = previous_value_ratio * sensorValue + new_value_ratio * analogRead(analogPin);
  //Serial.println(sensorValue);
  return sensorValue;
}

void toggleRelayBasedOnValueFromSensor(float sensorValue){
  int treshold = 750;
  int tresholdMargin = 20;
  
  if(sensorValue >= (treshold + tresholdMargin)){
    digitalWrite(relayPin, LOW);
  }
  else if(sensorValue <= (treshold - tresholdMargin)){
    digitalWrite(relayPin, HIGH);
  }
}

And here is the result:

But if i do it in that way:

/* 
  Sketch generated by the Arduino IoT Cloud Thing "Untitled"
  https://create.arduino.cc/cloud/things/992e25a6-d4ba-4196-b4e3-75b4b99ee50b 

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  float sensorValue;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"
#include "sensorVariables.h"

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  
  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
 */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();

  pinMode(relayPin, OUTPUT);
  sensorValue = analogRead(analogPin);
}

void loop() {
  sensorValue = getSensorValue(sensorValue);
  toggleRelayBasedOnValueFromSensor(sensorValue);
  ArduinoCloud.update();
}

float getSensorValue(float sensorValue)
{
  sensorValue = previous_value_ratio * sensorValue + new_value_ratio * analogRead(analogPin);
  Serial.println(sensorValue);
  return sensorValue;
}

void toggleRelayBasedOnValueFromSensor(float sensorValue){
  int treshold = 750;
  int tresholdMargin = 20;
  
  if(sensorValue >= (treshold + tresholdMargin)){
    digitalWrite(relayPin, LOW);
  }
  else if(sensorValue <= (treshold - tresholdMargin)){
    digitalWrite(relayPin, HIGH);
  }
}

The connection establish correctly (OFC there are few connection fails - but i think this is caused by NodeMCU boot up)
image

Do you know what could caused that?

There are many reasons why you could loose your internet connection and many articles on line such as