RobSmithDev
Published © CC BY-NC

Fireflies / Lightning Bugs in my Garden (yeah they're fake!)

Fireflies, or lightning bugs, one of natures miracles, In this tutorial I'll show you how to make your own!

IntermediateFull instructions provided2 hours19
Fireflies / Lightning Bugs in my Garden (yeah they're fake!)

Things used in this project

Hardware components

Arduino Pro Mini 328 - 5V/16MHz
SparkFun Arduino Pro Mini 328 - 5V/16MHz
×1
solar panel
×1
TP4056 Charger
×1
18650 Battery Holder
×1
Resistor 10k ohm
Resistor 10k ohm
×2
variable resistor (1M)
×1
LED WS2812B Copper Strings
×1
IRFZ44N Mosfet
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

3D Printed Box

Schematics

Schematics (now with MOSFET)

Code

Fireflies Code (Dusk Version)

C/C++
Full versions here: https://robsmithdev.co.uk/youtube/fireflies.zip
////////////////////////////////////////////////////////////////////////////////////////////////////
// Realistic FireFlies / Lightning Bugs                                                           //
// Created by Robert Smith                                                                        //
// https://www.youtube.com/c/robsmithdev                                                          //
// https://robsmithdev.co.uk                                                                      //
////////////////////////////////////////////////////////////////////////////////////////////////////
// Designed for ATMega328 microcontrollers.  The 'sleep' code may need modifying for others

#include <FastLED.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

#define MOSFET_POWER_CONTROL  4

// The data pin for the LEDs
#define LED_PIN     6

// Number of LEDs on the cable
#define NUM_LEDS    200

// Fade in/out time in milliseconds
#define FADETIME    50

// Maximum number of visible flies at a time
#define NUM_FLIES   10

// An array of LED values
CRGB leds[NUM_LEDS];

// A class to manage each fly
class Fly {  
  private:
    bool isYellowType;                // A yellow one flashes and moves, the white ones just twinkle  
    unsigned long when;               // When it should appear
    uint16_t duration;                 // How long for
    uint8_t targetLED;                // Which LED to control
  
    // For 'yellow' types
    uint8_t counter;                  // How many LEDs it can move along
    bool movementDirection;           // And in which direction (true is forward)
  
    // Returns the current brightness at this time, or -1 if the fly is 'dead'
    uint8_t getBrightness(const unsigned long now) {
      // Calculate elapsed time
      long elapsed = now - when;

      // Not on yet? brightness is 0
      if (elapsed<0) return 0;      
      
      // Fade in?
      if (elapsed < FADETIME) return map(elapsed,0,FADETIME,0,255);
      elapsed -= FADETIME;
      
      // Stay on during the duation
      if (elapsed < duration) return 255;
      elapsed -= duration;
  
      // Fade out
      if (elapsed >= duration) return 0;
      return map(elapsed,0,FADETIME,255,0);
    }
  
    // Get the colour we should show
    CRGB getColor(uint8_t brightness) {
      if (isYellowType) {
        return CRGB(brightness, brightness, 0);
      } else {
        return CRGB(brightness, brightness, brightness);
      }
    }
  
    // Handle the dead fly, depending on which type it is
    void handleDeadFly(const unsigned long now) {
      // If ran out of count, or its not a yellow one
      if ((counter==0) || (!isYellowType)) {
        reset(now);
      } else {
        // Move to the next one
        if (movementDirection) targetLED++; else targetLED--;
        counter--;
        when = now + 1000;  // see again 1 second from now
      }
    }
    
  public:

   // set which type this is
   void setYellow(bool isYellowType) {
      this->isYellowType = isYellowType;
   }

    // Reset the fly
    reset(const unsigned long now, const bool longerInitialDelay = false) {
      when = now + (random(1,5) * 1000);   // upto 5 seconds before used again, lower for more at once
      if (longerInitialDelay) when += random(1,10)*1000;  // this allows them to gracefully appear rather than all at once
      
      if (isYellowType) {      
        movementDirection = random(0,2)==1;   // Movement direction      
        counter = random(2,10);       // Number of movements
  
        if (movementDirection)  // forward?
          targetLED = random(NUM_LEDS/2,NUM_LEDS-counter);      // To start anywhere remove the NUM_LEDS/2
        else // backwards
          targetLED = random((NUM_LEDS/2) + counter,NUM_LEDS);  // To start anywhere remove the (NUM_LEDS/2)

         duration = random(50,100);

      } else {
        // Random flash
        duration = random(50,100);
        targetLED = random(0,NUM_LEDS/2);  // If you want these to appear anywhere, remove the /2
      }    

      duration += FADETIME * 2;
    }


  // Run the fly
  void run(const unsigned long now) {
    long elapsed = now - when;
    
    // Has animation elapsed?
    if (elapsed > duration + FADETIME + FADETIME) {
      // Ensure its off
      leds[targetLED] = CRGB(0,0,0);
      // Reset
      handleDeadFly(now);
    }

    // Animate the LED
    leds[targetLED] = getColor(getBrightness(now));
  }
};


Fly flies[NUM_FLIES];
bool inDayMode = true;


void prepareAllFlies(const unsigned long now) {
    randomSeed(analogRead(A1)); // seed based off random noise as the pin isn't connected

    // Reset all flies
    for (uint8_t fly=0; fly<NUM_FLIES; fly++) { 
	  // This gives us a small number of yellow ones
      flies[fly].setYellow( fly < (NUM_FLIES/4) );
      flies[fly].reset(now, true);
    }  
}

void setup() {
    delay( 300 );
    FastLED.addLeds<WS2811, LED_PIN, RGB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  10 );
    pinMode(MOSFET_POWER_CONTROL, OUTPUT);   // MOSFET control
    digitalWrite(MOSFET_POWER_CONTROL, LOW);  // Turn ON to setup

    pinMode(A2, INPUT);
    pinMode(A1, INPUT);
    pinMode(A0, INPUT);
    pinMode(LED_PIN, OUTPUT);

    prepareAllFlies(millis());
}

// watchdog interrupt, just used to disable the watchdog
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  

void loop()
{
    // See if theres a small voltage coming from the solar panel
    uint16_t voltage = analogRead(A0);

    // The values here are different to prevent flicking as we move between the two
    bool shouldBeInDayMode = voltage > 150; 
    bool shouldBeInNightMode = voltage < 100;
    
    // Has the state changed?
    if ((shouldBeInDayMode || shouldBeInNightMode) && (shouldBeInDayMode != inDayMode)) {
       inDayMode = shouldBeInDayMode;

       // If we went to day mode then turn the LEDs off
       if (inDayMode) {
         FastLED.clear(true);
       } else {
         prepareAllFlies( millis() );
       }
    }

    if (inDayMode) {
      digitalWrite(MOSFET_POWER_CONTROL, LOW);  // Turn OFF the Mosfet and thus the power to the LEDs
      FastLED.clear(true);
      // We want to put the chip to sleep. Interrupts are off, millis won't work, but we dont need them.
      // We'll be using the hardware watchdog to 'wake' from sleep, enable it for an 8 second sleep cycle
      // But we dont want the watchdog to reset the system, just wake up. So we make it call an interrupt, which we dont bother implementing
      WDTCSR |= bit(WDCE) | bit(WDE);               // This line allows changes to be made to the watchdog
      WDTCSR = bit(WDIE) | bit(WDP0) | bit(WDP3);   // enable watchdog timer interrupt (no reset), for 8 seconds delay
      wdt_reset();                                  // Reset the timeout      
      // We'll put the chip into Power Down state, which can only be woken by INT0, INT1, Pin Change Interrupts, and the Watchdog Timer (we disabled BOD - brown-out detection)
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);   
      noInterrupts();   
      sleep_enable();
      //sleep_bod_disable();
      interrupts();
      sleep_cpu();         // Zzzzzzzzzzzzzzzz
      sleep_disable();                  
    } else {
      digitalWrite(MOSFET_POWER_CONTROL, HIGH);  // Turn ON the Mosfet and thus the power to the LEDs
      // Run the firefly simulation
      unsigned long now = millis();
      
	  // Update each fly
      for (uint8_t a=0; a<NUM_FLIES; a++) 
        flies[a].run(now);

      // Set brightness based on the value from A2 (variable resistor between 0 and 5v)
      FastLED.setBrightness(map(analogRead(A2),0,1023,10,255));
	  
	  // Update output
      FastLED.show();
	  
	  // And pause
      FastLED.delay(10);      
    }
}

Credits

RobSmithDev

RobSmithDev

5 projects • 17 followers

Comments

Add projectSign up / Login