Table of contents
Abstract
A set of LED Spiral christmas tree as a scoreboard for good deeds and BLE tracker that guides my son and friends to his hidden gift. A learning and game for kindness and good value
Project
The Concept
I always wanted to teach my son and girlfriend's daughter the lessons of keeping track of goals. Also, I was good in Trekking and i can see how much my son is interested in traveling and so i thought maybe combine the two into a game using Christmas as an excuse. Initially my plan was only to do the tracking game alone using custom PCB using NRF52832 which has been lying in my drawer for a long time, and have one set as BLE beacon, and other as the tracker which gives out visual alert based on the RSSI value. I got inspiration of this game from my Garmin Instinct watch which helps me figure out where my phone is using a strength meter allowing me to trace it even if the sound alert emitted by phone is not audible. So, i made two designs of PCB, one for my son in a bracelet format, and the other in an earpiece jewelry for my girlfriend's daughter. I thought it will double as a sweet personalized gift for my girlfriend also.

But, here the quote "No plan survives first contact with the enemy" worked perfectly, as my PCBWay shipment got stuck with FedEx due to customs reason. So had to improvise. So i searched my inventory and found some old custom PCB which i used as proof of concept idea of my Aura alert project (Check out that project here) which i made in early 2025. It had esp32 and LEDs. But i felt that this alone was not enough for this competition I also wanted to preserve the full experience of naughty and good list, finding gifts under the Christmas tree. So here is my final plan
The Other Concept
Make a 3D Printed Spiral Christmas tree with LED lighting up the spiral. The BLE Tracker and Beacon will be encased in a Christmas tree design casing. I can use the addressable LED to use the spiral as a progress bar to keep track of good deeds. The BLE beacons will broadcasts signal every 10 secs. The BLE Trackers will listen to the beacons and based on the Distance taken from RSSI value breathe LED, the speed of which is faster if its closer to the beacon. For now i will control the progress of good deeds using buttons on the tree, but if time permits i will control it using BLE itself, Once the Progress bar is completed, the Star at the top of the Tree will light up and activate the tracker. Then, the person can go and figure out where I've hidden the gift. In effect, the key to the gift is kept under the tree.

Case design
I got less than a week so the first thing i did was design the concept on a paper and model it on SolidWorks. Get it 3D printed with a circular tube going in a spiral. But the spiral which i thought to be elegant turned to look like an popular brown emoji. That's when i realized my mechanical engineering brain over-rode the design sense. Why? Circular cross section is structurally more stable than the rectangular which gives better ribbon look. Later i found an spiral on Thingiverse too. https://www.thingiverse.com/thing:7216904/files. I still went ahead and redid the design myself, but then 3D printing effort cooked spaghetti and i did not have time to retry it. I decided to go ahead with the circular tube spiral. I wrapped the led strip around it, and attached a star on top of it.




The Code
The PCB which i am using for the tracker and the BLE beacon has ESP32, WS2812B, MCP73831 (Battery Charger), AP2112K (3.3V LDO) which i will be using. The OLED, Haptic motor driver and switches i will not be using. As i said this PCB was designed for another project, but i made a mistake in the power sharing circuitry and thus had to do patchwork to get the battery charging correct. Regardless you can recreate this using any Feather ESP32 board, use regular LED instead of the RGB LED.
Code for the BLE Beacon
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEAdvertising.h>
#include "esp_sleep.h"
#include <Arduino.h>
#define SLEEP_TIME_SEC 15
#define ADV_TIME_MS 1500 // advertise for 1.5 seconds
void setup() {
Serial.begin(115200);
delay(200);
// Init BLE
BLEDevice::init("GiftBeacon2");
BLEAdvertising *advertising = BLEDevice::getAdvertising();
advertising->setScanResponse(false);
advertising->setMinPreferred(0x06);
advertising->setMaxPreferred(0x12);
// Start advertising
BLEDevice::startAdvertising();
Serial.println("Beacon advertising...");
delay(ADV_TIME_MS);
// Stop advertising
BLEDevice::stopAdvertising();
Serial.println("Going to sleep");
// Deep sleep
esp_sleep_enable_timer_wakeup(SLEEP_TIME_SEC * 1000000ULL);
esp_deep_sleep_start();
}
void loop() {
// never reached
}
Code for the Tracker
#include <BLEDevice.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <Adafruit_NeoPixel.h>
#include "esp_sleep.h"
#define TARGET_NAME "GiftBeacon2"
#define LED_PIN 26
#define LED_COUNT 3
#define SCAN_TIME_SEC 20
#define SLEEP_TIME_SEC 10
Adafruit_NeoPixel pixels(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
bool beaconFound = false;
int bestRSSI = -1000;
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice device) {
if (device.haveName() && device.getName() == TARGET_NAME) {
beaconFound = true;
if (device.getRSSI() > bestRSSI) {
bestRSSI = device.getRSSI();
}
}
}
};
// ---------- LED EFFECTS ----------
void blinkRedFast(int times) {
for (int i = 0; i < times; i++) {
pixels.fill(pixels.Color(255, 0, 0));
pixels.show();
delay(120);
pixels.clear();
pixels.show();
delay(120);
}
}
void breatheWhite(int delayMs) {
for (int b = 0; b <= 255; b += 6) {
pixels.fill(pixels.Color(b, b, b));
pixels.show();
delay(delayMs);
}
for (int b = 255; b >= 0; b -= 6) {
pixels.fill(pixels.Color(b, b, b));
pixels.show();
delay(delayMs);
}
}
// ---------- RSSI → 10 STEP MAPPING ----------
int rssiToStep(int rssi) {
if (rssi >= -49) return 10;
if (rssi >= -54) return 9;
if (rssi >= -59) return 8;
if (rssi >= -64) return 7;
if (rssi >= -69) return 6;
if (rssi >= -74) return 5;
if (rssi >= -79) return 4;
if (rssi >= -84) return 3;
if (rssi >= -89) return 2;
return 1;
}
int stepToDelay(int step) {
// Step 1 = slowest, Step 10 = fastest
return map(step, 1, 10, 30, 4);
}
// ---------- SETUP ----------
void setup() {
Serial.begin(115200);
delay(500);
pixels.begin();
pixels.clear();
pixels.show();
BLEDevice::init("");
BLEScan *scan = BLEDevice::getScan();
scan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
scan->setActiveScan(true);
Serial.println("Scanning for GiftBeacon2...");
scan->start(SCAN_TIME_SEC, false);
if (!beaconFound) {
Serial.println("Beacon NOT found");
blinkRedFast(3);
} else {
int step = rssiToStep(bestRSSI);
int delayMs = stepToDelay(step);
Serial.print("Beacon found | RSSI: ");
Serial.print(bestRSSI);
Serial.print(" | Step: ");
Serial.println(step);
for (int i = 0; i < 3; i++) {
breatheWhite(delayMs);
}
}
pixels.clear();
pixels.show();
Serial.println("Sleeping...");
esp_sleep_enable_timer_wakeup(SLEEP_TIME_SEC * 1000000ULL);
esp_deep_sleep_start();
}
void loop() {}
The Beacon advertises for 1.5Sec and sleeps for 15 seconds. The tracker scans for 20 seconds and sleeps for 10 seconds. This way, battery can be conserved and also the searching time for gift can be deliberately slowed down for better experience by building some excitement.
Here is a video of the tracking done at my Parking space.
For the Controlling of Spiral tree, due to time constrains i used my Aura Hex PCB from my last project, and we got some wonderful effects.

and here is the final - Keys to the Gifts under the Christmas Tree
And yeah, was listening "Good bad Ugly". I love the background music
The Conclusion
I am super happy that i was able to get a very crude albeit working model of the project i had in mind and more importantly i was able to repurpose my old PCB for a new breath of life. I still don't like the spiral with circular cross section and will reprint proper one, after some careful placement of the supports. Maybe i can make it as a DNA also as a regular lamp. If anyone wants to share my 3D Printing frustration, take a look at video which i will post in a comment soon. I am not responsible if you punch your monitor.
References
- https://gitlab.com/arvindsa/christmas-tree-ear-ring
- https://www.thingiverse.com/thing:7216904/files
- AuraAlert - Lighting up Every Sound
