Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



Boblight - add ambi...
 
Share:
Notifications
Clear all

[Solved] Boblight - add ambient light detection

23 Posts
3 Users
0 Likes
4,157 Views
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

This is a continuation of IzeMan's comments with the Boblight article

The idea is to add some kind of ambient light detection and adjust the Boblight brightness accordingly.


   
ReplyQuote
(@izeman)
New Member
Joined: 8 years ago
Posts: 3
 

Thanks Hans.
Ii will sum up here what happened so for so we don't have to go back and forth between the 2 pages.
I have this light sensor http://www.aliexpress.com/item/Light-Sensor-Module-Photoresistor-Module-Seek-Light-Module-For-Arduino-Smart-Car/32414864057.html which is a simple on/off switch with a definable light level. It now outputs a voltage between 0 and 3.6V depending on light level.
And i will sum up the changes to the original code here:

int BRIGHTNESS = 90;         // make sure this stays within 0...100

and in the loop:

int lightPin = analogRead(A0);  //define a pin for Photo resistor input (value 0-1023)
strip.setBrightness(lightPin/10.23); //divide input by 10.23 gives a value of 0-100

I "guess" it works as with a simple 

<span style="color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; line-height: 20px; white-space: pre-wrap; text-align: initial; background-color: rgb(248, 248, 248);">Serial.println(strip.setBrightness); // print value on serial console</span>

it shows me the correct value in the serial console. The problem now is that the ambilight comes to an almost complete STALL. Changes in color happen every minute or so. So it seems that reading the analogue port takes too much time.
Changing the BRIGHTNESS every 10s or so would be totally enough. So i thought i could use a second arduino nano to collect the senor data and send the value every 10s to the "main" arduino.
The question now is to find the right method to collect a value from either an analogue or digital input port w/o slowing the loop down.

The other question: Does a non integer value for brightness work? Haven't checked yet.

   
ReplyQuote
(@izeman)
New Member
Joined: 8 years ago
Posts: 3
 

I have another idea: Reading analogue pins takes time. I guess even the fast reads would slow the nano down too much.

Reading digital pins only recevied two states: HIGH and LOW. so i could set a DAY or NIGHT setting. This can be done with the light sensor as is. This will be the first try.

If i want more states, i could use second nano that reads the sensor every 10s or so, and sets 2 digital output pins for 4 different settings or 3 digital pins for 8 brightness settings that could easily read by 3 digital input pins of the main nano.

What do you think?


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

If you set only 2 states, then you could use a light sensitive transistor (Phototransistor) or diode. They only know ON and OFF (in essence).

I did find a topic in the Arduino Forum about this: link.
I have attached an image I found for the way to hook it up.

I would not use a second Nano, but it sure would work the way you described it.

If you'd like multiple intervals, you could use multiple Photo transistors or diodes.
As far as I can see, the resistor in the schematic determines how sensitive it is. A small potentiometer could be used to tune them.
Say you'd use 2 of these, so we can determine dark, semi dark, light and very light, then on resistor could be used to determine light and one semi dark.
You'll have to play a bit with that. I do not have such a diode or transistor so I'd have to order one or two before I can pay with that. But the idea would be the same as using a second nano, and I'd expect it to be cheaper.


   
ReplyQuote
(@izeman)
New Member
Joined: 8 years ago
Posts: 3
 

Sure. You could use two or more sensors :) They are damn cheap (~1$). This may be the most simple way to do it.

If i got time i will start with one sensor and it's on/off feature.

How would you determine 4 states with 2 switches? Each one has ON/OFF. That's it. If it's dark both of them are OFF, if there is some light one might switch to ON, and if there is even more light the second one will switch to ON. So it's only 3 states.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

Note that with the schematic you can also swap resistor and transistor if you want it to work opposite.

Another link I found: Arduino Forum which is more geared towards infrared detection, but the principle (different transistor of course) should be the same.

Some useful links I found:

Arduino Forum, LDR to digital, StackExchange


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

Sorry - was still writing my first reply while you already posted a reply yourself haha ...

Yeah it would be 3 or 4 states: ON+ON, ON+OFF, OFF+ON and OFF+OFF, but I agree that there will be an overlap, so you'd probably end up with "only" 3 states, which is probably not bad either: Daylight, Evening with room lights on, Evening with room lights off. Something like that anyway.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

In the meanwhile, I'll go dig through my stuff and see if I have anything laying around to try this here as well. 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

It seems that an LDR can be hooked up to a digital pin directly as well.
Which makes sense (see this Arduino Forum topic), as the Arduino digital pins read a particular voltage as HIGH and below that as LOW.

From that post:

Why do you think you need a transistor? Why not connect LDR + resistor to digital pin directly? Arduino has threshold 2.7V low to high, build-in Schmidt trigger with hysteresis 0.5V (2.2V high to low) . Varying value of resistor you 'd easily set luminance level point


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

Well, I have been working with LDR's for the past few hours now (and writing an article while I was at it).
Working with 2 LDRs actually works pretty good. Of course I have not yet tested this with Boblight - I've just been exploring the mechanics 

I hope to finish the article tomorrow (it's midnight here - only have to finish translation to Dutch) and post my findings.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

I finished the article, and even added using 2 LDRs.
Let's see how useful those LDRs can be in the Boblight setup ...

Here is the link: Arduino - Playing with LDRs

Let me know what you think 


   
ReplyQuote
(@castaway)
Active Member
Joined: 8 years ago
Posts: 6
 

Hello guys, i did finished my Ambilight project with hyperion works just perfect! Now i want to add LDR sensor to save some energy to run Ambilight only if there is dark in room. i did it and it works BUT.

there are states when my LED strip blink like crazy it happen somewhere betwean states like it cant chose if its 1 or 0 so it blink all colors. If i cover sensor its ok and Amblight working, if i light on it it work nice it turn OFF ambilight but if i light it just barelly it make crazy things. Im used digital pin

Light -  brigtness to "0"
Dusk - brightness to "70"

here is my code, Anybody have working LDR? any way i can fix this issue? i did try adjust it with potentiometer but cant fix it with it.

/* Modified and commented by ai.rs
   t4a_boblight
   (C) 2014 Hans Luijten, www.tweaking4all.com
   t4a_boblight is free software and can be distributed and/or modified
   freely as long as the copyright notice remains in place.
   Nobody is allowed to charge you for this code.
   Use of this code is entirely at your own risk.
*/
#include "Adafruit_NeoPixel.h"
// DEFINITIONS
#define STARTCOLOR 0x333333 // LED colors at start
#define BLACK 0x000000 // LED color BLACK
#define DATAPIN 5 // Datapin
#define LEDCOUNT 202 // Number of LEDs used for boblight
// LEDCOUNT value is local value in Arduino sketch, for hyperion it doesn't matter it sends prefx characters according to hyperion config
#define SHOWDELAY 200 // Delay in micro seconds before showing default 200
#define BAUDRATE 500000// Serial port speed, 460800 tested with Arduino Uno R3 23400 za MEGA, 115200 nano
//#define BRIGHTNESS 70 // Max. brightness in %
#define LDRpin 8 //pin kde je senzor
//Hyperion sends prefix characters based on number of LEDs in config file
// e.g. for 181 LEDs it will send 0xB4 and cheksum 0xE1
// keep in mind if you are using boblight config to calculate prefix that Boblight counts diodes from 1 and Hyperion from 0
// if you have problems try +1 or -1 diodes when generating prefix characters
// values to save some time: 178 B1 E4, 180 B3E6, 181 B4E1, 182 B5E0
//hyperion code
//_ledBuffer[3] = ((ledValues.size() - 1) >> 8) & 0xFF; // LED count high byte
// _ledBuffer[4] = (ledValues.size() - 1) & 0xFF; // LED count low byte
// _ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
const char prefix[] = {0x41, 0x64, 0x61, 0x00, 0xC9, 0x9C}; // Start prefix ADA
char buffer; // Temp buffer for receiving prefix data
// Init LED strand, WS2811/WS2912 specific
// These might work for other configurations:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDCOUNT, DATAPIN, NEO_GRB + NEO_KHZ800);
int state; // Define current state
#define STATE_WAITING 1 // - Waiting for prefix
#define STATE_DO_PREFIX 2 // - Processing prefix
#define STATE_DO_DATA 3 // - Handling incoming LED colors
int readSerial; // Read Serial data (1)
int currentLED; // Needed for assigning the color to the right LED
int BRIGHTNESS = 70; // make sure this stays within 0...100 TU
void setup()
{
  strip.begin(); // Init LED strand, set all black, then all to startcolor
  strip.setBrightness( (255 / 100) * BRIGHTNESS );
  setAllLEDs(BLACK, 0);
  setAllLEDs(STARTCOLOR, 5);
  Serial.begin(BAUDRATE); // Init serial speed
  state = STATE_WAITING; // Initial state: Waiting for prefix
}

void loop()
{
  
    switch (state)
    {
      case STATE_WAITING: // Waiting for prefix
        if ( Serial.available() > 0 )
        {
          readSerial = Serial.read(); // Read one character
          if ( readSerial == prefix[0] ) // if this character is 1st prefix char
          {
            state = STATE_DO_PREFIX; // then set state to handle prefix
          }
        }
        break;

      case STATE_DO_PREFIX: // Processing Prefix
        if ( Serial.available() > sizeof(prefix) - 2 )
        {
          Serial.readBytes(buffer, sizeof(prefix) - 1);
          for ( int Counter = 0; Counter < sizeof(prefix) - 1; Counter++)
          {
            if ( buffer[Counter] == prefix[Counter + 1] )
            {
              state = STATE_DO_DATA; // Received character is in prefix, continue
              currentLED = 0; // Set current LED to the first one
            }
            else
            {
              state = STATE_WAITING; // Crap, one of the received chars is NOT in the prefix
              break; // Exit, to go back to waiting for the prefix
            } // end if buffer
          } // end for Counter
        } // end if Serial
        break;

      case STATE_DO_DATA: // Process incoming color data
        if ( Serial.available() > 2 ) // if we receive more than 2 chars
        {
          Serial.readBytes( buffer, 3 ); // Abuse buffer to temp store 3 charaters
          strip.setPixelColor( currentLED++, buffer[0], buffer[1], buffer[2]); // and assing to LEDs
        }
        if ( currentLED > LEDCOUNT ) // Reached the last LED? Display it!
        {
          strip.show(); // Make colors visible
          delayMicroseconds(SHOWDELAY); // Wait a few micro seconds
          state = STATE_WAITING; // Reset to waiting ...
          currentLED = 0; // and go to LED one
          break; // and exit ... and do it all over again
        }
        break;
    } // switch(state)
    strip.setBrightness( (255 / 100) * BRIGHTNESS );
 AdjustBrightness();
  } // loop

  // Sets the color of all LEDs in the strand to 'color'
  // If 'wait'>0 then it will show a swipe from start to end
  void setAllLEDs(uint32_t color, int wait)
  {
    for ( int Counter = 0; Counter < LEDCOUNT; Counter++ ) // For each LED
    {
      strip.setPixelColor( Counter, color ); // .. set the color
      if ( wait > 0 ) // if a wait time was set then
      {
        strip.show(); // Show the LED color
        delay(wait); // and wait before we do the next LED
      } // if wait
    } // for Counter
    strip.show(); // Show all LEDs
  } // setAllLEDs
  void AdjustBrightness() {
  int LDRValue = 0; // result of reading the digital pin
  
  LDRValue = digitalRead(LDRpin);// read the value from the LDR
  
  if(LDRValue==1) { 
    BRIGHTNESS = 0;
    // Light, so set LED brightness to 0%
  }
  else { 
    BRIGHTNESS = 70;
    // Dark,so set LED brightness to 70%
  }
  }

  


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

Thanks Castaway for posting your work.
Nice!!! 

In those moments where the light in your room reaches a "borderline" amount of light, the digital pin will most likely start fluctuating between "on" and "off" and this is probably what you're seeing right now.

So ... first of all I'd use an analog pin, if possible speed wise. With the analog pin we'd have better control over the values read.

Another option, come to think of it, is to slow down the effect of a read value.
What I mean with that, is that a detected value should at least be working for a couple seconds before changing it's state.

So in words: if we start detecting and we see that it's dark in the room (LEDs should be ON), and we go through the AdjustBrightness function and we have not yet reached our "count", then leave brightness as is. If during the "count" we see again a detection of "dark room", restart the counting. If we exceed our count threshold and the LDR still says "light room", then and only then switch state (LEDs OFF), and repeat the same cycle.

I hope I explained what I was thinking right haha ...

Let me try this in code (untested):

...
int BrightnessCounter 0;
#define MaxBrightnessCount 1000;
... void AdjustBrightness() {
    int LDRValue = 0; // result of reading the digital pin  
    LDRValue = digitalRead(LDRpin);// read the value from the LDR
    // if we detect the same brightness as before, reset counter
    if( ((LDRValue==1) && (BRIGHTNESS==0)) || ((LDRValue!=1) && (BRIGHTNESS==70)) ) {
      BrightnessCounter = 0; 
    }
    // However, if we exceeded the counter max, then set new brightness
    else if(BrightnessCounter>=MaxBrightnessCount) {
      if(LDRValue==1) {  
        BRIGHTNESS = 0; // Light, so set LED brightness to 0%
      } else { 
        BRIGHTNESS = 70; // Dark,so set LED brightness to 70%
      }
    }
    
   BrightnessCounter++; // increase counter
}

I've defined a new variable (BrightnessCounter) and a "constant" (MaxBrightnessCount).
If we see that the current brightness is still valid and the same: Reset counter.
If this is not the case, AND we exceeded the MaxBrightnessCount value, then determine the proper Brightness again.

You might need to test and play with the MaxBrightnessCount ... but this is what I;d start playing with.
Since I don't have a setup with an LDR, I can't really test this.
Please let us know how this worked out ... 


   
ReplyQuote
(@castaway)
Active Member
Joined: 8 years ago
Posts: 6
 

Hello my friend thank you for helping me!
i use your code but i have to modity this two rows to sucefully compile

int BrightnessCounter = 0;
#define MaxBrightnessCount 1000

(added "=" and deleted ";")

Im not sure right now if it working because it change state immediatly no delay as i expect to(im lighting sensor with flashlight). But time will show if it working or not.To be honest i have this LDR setup online just second day and there was not opportunity see it in action with sunlight and real conditions.

Here is my code if you are interested in:

/* Modified and commented by ai.rs
   t4a_boblight
   (C) 2014 Hans Luijten, www.tweaking4all.com
   t4a_boblight is free software and can be distributed and/or modified
   freely as long as the copyright notice remains in place.
   Nobody is allowed to charge you for this code.
   Use of this code is entirely at your own risk.
*/
#include "Adafruit_NeoPixel.h"
// DEFINITIONS
#define STARTCOLOR 0x333333 // LED colors at start
#define BLACK 0x000000 // LED color BLACK
#define DATAPIN 5 // Datapin
#define LEDCOUNT 202 // Number of LEDs used for boblight
// LEDCOUNT value is local value in Arduino sketch, for hyperion it doesn't matter it sends prefx characters according to hyperion config
#define SHOWDELAY 200 // Delay in micro seconds before showing default 200
#define BAUDRATE 500000// Serial port speed, 460800 tested with Arduino Uno R3 23400 za MEGA, 115200 nano
//#define BRIGHTNESS 70 // Max. brightness in %
#define LDRpin 8 //pin kde je senzor
//Hyperion sends prefix characters based on number of LEDs in config file
// e.g. for 181 LEDs it will send 0xB4 and cheksum 0xE1
// keep in mind if you are using boblight config to calculate prefix that Boblight counts diodes from 1 and Hyperion from 0
// if you have problems try +1 or -1 diodes when generating prefix characters
// values to save some time: 178 B1 E4, 180 B3E6, 181 B4E1, 182 B5E0
//hyperion code
//_ledBuffer[3] = ((ledValues.size() - 1) >> 8) & 0xFF; // LED count high byte
// _ledBuffer[4] = (ledValues.size() - 1) & 0xFF; // LED count low byte
// _ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
const char prefix[] = {0x41, 0x64, 0x61, 0x00, 0xC9, 0x9C}; // Start prefix ADA
char buffer; // Temp buffer for receiving prefix data
// Init LED strand, WS2811/WS2912 specific
// These might work for other configurations:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDCOUNT, DATAPIN, NEO_GRB + NEO_KHZ800);
int state; // Define current state
#define STATE_WAITING 1 // - Waiting for prefix
#define STATE_DO_PREFIX 2 // - Processing prefix
#define STATE_DO_DATA 3 // - Handling incoming LED colors
int readSerial; // Read Serial data (1)
int currentLED; // Needed for assigning the color to the right LED
int BRIGHTNESS = 70; // make sure this stays within 0...100 TU
int BrightnessCounter = 0;
#define MaxBrightnessCount 1000

void setup()
{
  strip.begin(); // Init LED strand, set all black, then all to startcolor
  strip.setBrightness( (255 / 100) * BRIGHTNESS );
  setAllLEDs(BLACK, 0);
  setAllLEDs(STARTCOLOR, 5);
  Serial.begin(BAUDRATE); // Init serial speed
  state = STATE_WAITING; // Initial state: Waiting for prefix
}

void loop()
{
  
    switch (state)
    {
      case STATE_WAITING: // Waiting for prefix
        if ( Serial.available() > 0 )
        {
          readSerial = Serial.read(); // Read one character
          if ( readSerial == prefix[0] ) // if this character is 1st prefix char
          {
            state = STATE_DO_PREFIX; // then set state to handle prefix
          }
        }
        break;

      case STATE_DO_PREFIX: // Processing Prefix
        if ( Serial.available() > sizeof(prefix) - 2 )
        {
          Serial.readBytes(buffer, sizeof(prefix) - 1);
          for ( int Counter = 0; Counter < sizeof(prefix) - 1; Counter++)
          {
            if ( buffer[Counter] == prefix[Counter + 1] )
            {
              state = STATE_DO_DATA; // Received character is in prefix, continue
              currentLED = 0; // Set current LED to the first one
            }
            else
            {
              state = STATE_WAITING; // Crap, one of the received chars is NOT in the prefix
              break; // Exit, to go back to waiting for the prefix
            } // end if buffer
          } // end for Counter
        } // end if Serial
        break;

      case STATE_DO_DATA: // Process incoming color data
        if ( Serial.available() > 2 ) // if we receive more than 2 chars
        {
          Serial.readBytes( buffer, 3 ); // Abuse buffer to temp store 3 charaters
          strip.setPixelColor( currentLED++, buffer[0], buffer[1], buffer[2]); // and assing to LEDs
        }
        if ( currentLED > LEDCOUNT ) // Reached the last LED? Display it!
        {
          strip.show(); // Make colors visible
          delayMicroseconds(SHOWDELAY); // Wait a few micro seconds
          state = STATE_WAITING; // Reset to waiting ...
          currentLED = 0; // and go to LED one
          break; // and exit ... and do it all over again
        }
        break;
    } // switch(state)
    strip.setBrightness( (255 / 100) * BRIGHTNESS );
 AdjustBrightness();
  } // loop

  // Sets the color of all LEDs in the strand to 'color'
  // If 'wait'>0 then it will show a swipe from start to end
  void setAllLEDs(uint32_t color, int wait)
  {
    for ( int Counter = 0; Counter < LEDCOUNT; Counter++ ) // For each LED
    {
      strip.setPixelColor( Counter, color ); // .. set the color
      if ( wait > 0 ) // if a wait time was set then
      {
        strip.show(); // Show the LED color
        delay(wait); // and wait before we do the next LED
      } // if wait
    } // for Counter
    strip.show(); // Show all LEDs
  } // setAllLEDs
  void AdjustBrightness() {
  int LDRValue = 0; // result of reading the digital pin
  LDRValue = digitalRead(LDRpin);// read the value from the LDR
// if we detect the same brightness as before, reset counter
    if( ((LDRValue==1) && (BRIGHTNESS==0)) || ((LDRValue!=1) && (BRIGHTNESS==70)) ) {
      BrightnessCounter = 0; 
    }
    // However, if we exceeded the counter max, then set new brightness
    else if(BrightnessCounter>=MaxBrightnessCount) {
  if(LDRValue==1) { 
    BRIGHTNESS = 0;
    // Light, so set LED brightness to 0%
  }
  else { 
    BRIGHTNESS = 70;
    // Dark, so set LED brightness to 70%
  }
   }
  
   BrightnessCounter++; // increase counter
  } 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2676
Topic starter  

Thanks Casteaway!

You're most welcome. Sorry for the typo's, I had to type the code without being able to test it.
You could of course increase the 1000 to for example 10000 - see what works better.
I'll be curious of you findings, please let us know how it works out 


   
ReplyQuote
Page 1 / 2
Share: