Built-in project · Arduino Uno R3

New Year's countdown on an Arduino Uno

A DS3231 and a four-digit display count down to midnight on New Year’s Eve, then a ring of WS2812B LEDs bursts into fireworks and the display shows the new year. The whole build, an Arduino Uno and 4 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate Runs in your browser. Free, and no account needed.

New Year's countdown · Arduino Uno R3live0.000 s 0.00x
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// New Year's countdown: a clock for the party that counts down to midnight on
// a four-digit display, then sets off fireworks on a ring of LEDs.
//
//   DS3231    SCL -> A5   SDA -> A4   VCC -> 5 V   GND -> GND
//   TM1637    CLK -> pin 4   DIO -> pin 5   VCC -> 5 V   GND -> GND
//   LED ring  16 WS2812B LEDs, DIN <- 330 ohms <- pin 6, VDD -> 5 V, VSS -> GND
//
// The display shows the time left: hours and minutes until the last hour,
// then minutes and seconds, so the final minute reads 00:59, 00:58 ... 00:00.
// At midnight the ring bursts into fireworks for a minute, and the display
// shows the new year.
//
// The target is worked out from the clock, never typed in: midnight at the
// start of January 1st of the year after the one the clock is in. So the same
// sketch counts down every December 31st, year after year.
//
// Set the clock once: uncomment the rtc.adjust() line, upload, then comment it
// out and upload again. In the simulator the clock starts 15 seconds before
// midnight, so you can watch the moment arrive.
//
// Things to try. Make the fireworks last longer with SHOW_SECONDS. Change the
// colors in PALETTE to your own.

#include <Wire.h>
#include <RTClib.h>
#include <TM1637Display.h>
#include <Adafruit_NeoPixel.h>

const int RING_PIN = 6;
const int LEDS = 16;
const unsigned long SHOW_SECONDS = 60;

RTC_DS3231 rtc;
TM1637Display display(4, 5);   // CLK, DIO
Adafruit_NeoPixel ring(LEDS, RING_PIN, NEO_GRB + NEO_KHZ800);

const uint32_t PALETTE[] = {0xFF2020, 0xFFD040, 0x40A0FF, 0x40FF60, 0xFF40C0, 0xFFFFFF};
const int COLORS = sizeof(PALETTE) / sizeof(PALETTE[0]);

uint32_t lastSecond = 0;
uint32_t showUntil = 0;
unsigned long nextFrame = 0;
uint8_t level[LEDS];
uint32_t color[LEDS];

// Midnight at the start of the next year.
uint32_t nextNewYear(const DateTime &now) {
  return DateTime(now.year() + 1, 1, 1, 0, 0, 0).unixtime();
}

void showLeft(uint32_t seconds) {
  uint32_t h = seconds / 3600;
  uint32_t m = (seconds / 60) % 60;
  uint32_t s = seconds % 60;
  int value = h > 0 ? (int)((h > 99 ? 99 : h) * 100 + m) : (int)(m * 100 + s);
  display.showNumberDecEx(value, 0b01000000, true);   // colon on
}

// One frame of fireworks: now and then a burst of one color lights a few
// LEDs around a random spot, and every LED fades a little each frame.
void fireworks() {
  if (random(0, 6) == 0) {
    int center = random(0, LEDS);
    uint32_t c = PALETTE[random(0, COLORS)];
    for (int d = -2; d <= 2; d++) {
      int i = (center + d + LEDS) % LEDS;
      level[i] = 255 - abs(d) * 60;
      color[i] = c;
    }
  }
  for (int i = 0; i < LEDS; i++) {
    uint8_t r = (uint8_t)(color[i] >> 16), g = (uint8_t)(color[i] >> 8), b = (uint8_t)color[i];
    ring.setPixelColor(i, r * level[i] / 255, g * level[i] / 255, b * level[i] / 255);
    level[i] = level[i] > 12 ? level[i] - 12 : 0;
  }
  ring.show();
}

void setup() {
  Serial.begin(9600);
  display.setBrightness(5);
  ring.begin();
  ring.setBrightness(180);
  ring.show();
  if (!rtc.begin()) {
    Serial.println("No DS3231 answered: check SDA and SCL");
    while (true) {
    }
  }
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));   // set once, see above
  randomSeed(analogRead(A0));
  Serial.println("New Year's countdown");
}

void loop() {
  if (showUntil > 0 && millis() >= nextFrame) {
    nextFrame = millis() + 30;
    fireworks();
  }

  DateTime now = rtc.now();
  uint32_t t = now.unixtime();
  if (t == lastSecond) return;
  lastSecond = t;

  // The first minute of January 1st: the show, and the new year on the display.
  if (now.month() == 1 && now.day() == 1 && now.hour() == 0 && now.minute() == 0) {
    if (showUntil == 0) {
      showUntil = t + SHOW_SECONDS;
      Serial.print("Happy New Year! Welcome to ");
      Serial.println(now.year());
    }
    display.showNumberDec(now.year(), false);
    return;
  }
  if (showUntil > 0 && t >= showUntil) {
    showUntil = 0;
    ring.clear();
    ring.show();
    Serial.println("Show over, counting to next year");
  }

  uint32_t left = nextNewYear(now) - t;
  showLeft(left);
  if (left <= 10) {
    Serial.println(left);
  } else if (now.second() == 0) {
    Serial.print(left / 60);
    Serial.println(" minutes to go");
  }
}

Parts list

6 parts, plus the jumper wires. Every one is in the editor's parts bin.

How it is wired

8 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.

  • Arduino Uno R3 pin 6; Resistor, 330 Ω pin 1
  • Arduino Uno R3 pin 5; Four-digit display, TM1637 pin DIO
  • Arduino Uno R3 pin 4; Four-digit display, TM1637 pin CLK
  • Arduino Uno R3 pin 5V; Real-time clock, DS3231 pin VCC; Four-digit display, TM1637 pin VCC; Addressable RGB LEDs pin VDD
  • Ground: Arduino Uno R3 pin GND; Real-time clock, DS3231 pin GND; Four-digit display, TM1637 pin GND; Addressable RGB LEDs pin VSS
  • Arduino Uno R3 pin A4; Real-time clock, DS3231 pin SDA
  • Arduino Uno R3 pin A5; Real-time clock, DS3231 pin SCL
  • Resistor, 330 Ω pin 2; Addressable RGB LEDs pin DIN

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.