Page 1 of 1

Boblight – add ambient light detection

Boblight – add ambient light detection

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.
Examples: "MacOS X - Your question", "MS Word - Your Tip or Trick".

Please note that switching to another language when reading a post will not work!
Posts will not have a translated counterpart.




RSS Feed

Home Forums Hardware Arduino Boblight – add ambient light detection

This topic contains 22 replies, has 3 voices, and was last updated by  hans 2 years, 11 months ago.

Viewing 15 posts - 1 through 15 (of 23 total)
  • Author
    Posts
  • 5259

    hans
    Keymaster

    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.

    5260

    izeman
    Participant

    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.
    5263

    izeman
    Participant

    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?

    5264

    hans
    Keymaster

    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.

    Attachments:
    5266

    izeman
    Participant

    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.

    5267

    hans
    Keymaster

    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

    5268

    hans
    Keymaster

    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.

    5269

    hans
    Keymaster

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

    5270

    hans
    Keymaster

    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

    5287

    hans
    Keymaster

    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.

    5289

    hans
    Keymaster

    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 

    5886

    castaway
    Participant

    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[sizeof(prefix)]; // 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%
      }
      }

      

    Attachments:
    5895

    hans
    Keymaster

    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 … 

    5907

    castaway
    Participant

    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[sizeof(prefix)]; // 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
      } 

    5912

    hans
    Keymaster

    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 

Viewing 15 posts - 1 through 15 (of 23 total)



You must be logged in to reply to this topic.