|
KiCADKicad
|
|
|
arduino IDEArduino
|
|
|
AWS IoT |
IoT Love Lantern
A few years ago, my fiancée and I were living worlds apart—she in Madrid, and I in Boston. Long-distance was hard, and we longed for a way to feel closer. That's when the idea of Love Lanterns was born.
It started as a simple dream: to create a physical way to share our thoughts and feelings, even from afar. After many nights of brainstorming and tinkering, the first iteration of our Love Lanterns came to life. Every time one of us touched our lantern, the other would light up, bridging the miles between us with a warm, comforting glow. It was our secret way of saying, “I'm thinking of you.”
The Love Lanterns became a cherished part of our routine, a little beacon of love in the midst of the distance. Seeing the light shine on the other side of the world made us feel closer, connected, and deeply loved.
Fast-forward to today, and the Love Lanterns have evolved into a polished PCB and are closer to becoming a product that others can enjoy. These IoT lanterns use an ESP32 module to communicate via the AWS IoT service, ensuring reliable and instant connectivity. They are designed to retrofit any lantern with a string of fairy lights (LED string), and the touch sensing is implemented through the metallic body of the lantern. With USB-C power, they offer maximum international compatibility, making them perfect for couples separated by oceans or borders.
Built using Arduino software, the Love Lanterns are not only a thoughtful gift, but also a fun DIY project that can bring people closer together through the joy of making. Each touch lights up your loved one’s lantern, just as it did for us, bridging the gap and illuminating your connection with a warm, heartfelt glow.
Whether you’re thousands of miles away or just around the corner, the Love Lanterns keep your bond bright and alive, one touch at a time.
Find the lantern used in the picture here: https://www.amazon.com/gp/product/B01J62PSVI
// Select device DEVICE_A or DEVICE_B
#define DEVICE_A
#include <AWS_IOT.h>
#include <WiFi.h>
#include "web_creds.h"
// Light settings
#define LEDC_CHANNEL_0 0 // first of 16 channels
#define LEDC_TIMER_13_BIT 13 // PWM timer precission
#define LEDC_BASE_FREQ 5000 // PWM base frequency
#define LED_PIN 21
#define LED_MAX_ALONE 200.0f
#define LED_MAX 255.0f
// Messaging settings
#define MAX_PUB_FAIL 5
#define MAX_TIME_NO_MSG 30000
#define MSG_LEN 16 // Message buffer length
#define MSG_MAX_PERIOD 10 // seconds
#define TICK_PERIOD 15 // milliseconds
#define FADE 4.0f // how much to dim the LED when not touched
// Touch settings
#define TOUCH_FILTER 0.085f
#define TOUCH_TH 0.8f
// Touch status
float touch = 0;
float touch_baseline = 12;
AWS_IOT iot;
// Flow status
uint8_t status = WL_IDLE_STATUS;
uint8_t pub_fail_cnt = 0;
uint32_t tick = 0;
unsigned long last_sub = 0;
bool msg_received = false;
bool must_pub = false;
char payload[MSG_LEN];
char last_payload[MSG_LEN];
char rcvd_payload[MSG_LEN];
// Light status
float brightness = LED_MAX_ALONE; // how bright the LED is
// Soft Reset
void(* resetSoftware)(void) = 0;
// Arduino-like analogWrite
// value must be between 0 and valueMax
void ledAnalogWrite(uint8_t channel, float val, uint32_t valueMax = 255) {
// calculate duty, 8191 from 2 ^ 13 - 1
uint32_t value = valueMax - ((int)val);
uint32_t duty = (8191 / valueMax) * min(value, valueMax);
ledcWrite(channel, duty); // write duty to LEDC
}
// AWS IoT subscribe callback
void subCallback (char *topicName, int payloadLen, char *payLoad) {
strncpy(rcvd_payload, payLoad, payloadLen);
rcvd_payload[payloadLen] = 0;
if (rcvd_payload[0] == 't') { // Check if payload correspond to "touch"
brightness = LED_MAX;
}
msg_received = true;
last_sub = millis();
}
// Initialization sequence
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
// Setup timer and attach timer to a led pin
ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
ledcAttachPin(LED_PIN, LEDC_CHANNEL_0);
delay(700);
// Lantern ID
Serial.println(web.client_id);
// Connect to WiFi
auto wifi_status_led = HIGH;
Serial.print("Connecting to ");
Serial.println(web.wifi_ssid);
while (status != WL_CONNECTED)
{
Serial.print(".");
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(web.wifi_ssid, web.wifi_password);
// Show connection status
for (int i = 0; i < 10; i++) {
digitalWrite(LED_BUILTIN, i % 2);
ledAnalogWrite(LEDC_CHANNEL_0, LED_MAX_ALONE * (i % 2));
Serial.print(".");
delay(500);
}
}
Serial.println("..");
Serial.print("Connected to ");
Serial.println(web.wifi_ssid);
// Connect to AWS
if (iot.connect(web.host_address, web.client_id) == 0)
{
Serial.println("Connected to AWS");
delay(1000);
if (0 == iot.subscribe(web.topic_sub, subCallback))
{
Serial.println("Subscribed to companion ʘ‿ʘ");
}
else
{
Serial.println("Subscription failed ¯\\(ʘ_ʘ)/¯"); // Check Thing Name and credentials
resetSoftware();
}
}
else
{
Serial.println("AWS connection failed, check the HOST Address");
resetSoftware();
}
// Initialize touch baseline
for (int i = 0; i < 2000; i += 15) {
touch = TOUCH_FILTER * touchRead(T0) + (1 - TOUCH_FILTER) * touch;
touch_baseline = 0.01 * touch + 0.99 * touch_baseline;
brightness = max(0.0f, brightness - FADE);
ledAnalogWrite(LEDC_CHANNEL_0, brightness);
delay(15);
}
last_sub = millis();
Serial.println("Lantern ready ♥‿♥");
}
// Main loop
void loop() {
// Reset if WiFi connection is lost
if (!WiFi.isConnected()) {
Serial.println("WiFI disconnected, resetting (x_x)");
resetSoftware();
}
// Read touch sensor
touch = TOUCH_FILTER * touchRead(T0) + (1 - TOUCH_FILTER) * touch;
sprintf(payload, "no touch"); // Initialize msg payload
// Track touch sensor baseline
if (touch > touch_baseline) {
touch_baseline = touch;
} else if (touch_baseline * TOUCH_TH > touch) { // Touched
sprintf(payload, "touch");
must_pub = true;
digitalWrite(LED_BUILTIN, HIGH);
brightness = min(LED_MAX_ALONE, brightness + FADE);
} else { // Not touched, track sensor baseline slowly
touch_baseline = 0.01 * touch + 0.99 * touch_baseline;
digitalWrite(LED_BUILTIN, LOW);
brightness = max(0.0f, brightness - FADE / 300.0f);
}
ledAnalogWrite(LEDC_CHANNEL_0, brightness);
if (msg_received)
{
msg_received = false;
Serial.print("Rec: ");
Serial.println(rcvd_payload);
}
// Publish to topic every MSG_MAX_PERIOD seconds or if new state detected
if (tick >= (MSG_MAX_PERIOD * 1000 / TICK_PERIOD) || (payload[0] != last_payload[0] && must_pub))
{
tick = 0;
must_pub = false;
pub_fail_cnt = 0;
while (pub_fail_cnt <= MAX_PUB_FAIL) {
Serial.print("Pub: ");
Serial.println(payload);
if (iot.publish(web.topic_pub, payload) == 0) {
memcpy(last_payload, payload, sizeof(payload[0])*MSG_LEN);
break;
}
else
{
Serial.println("Pub fail (⊙_⊙')");
// Count number of fails
if (++pub_fail_cnt == MAX_PUB_FAIL) {
Serial.println("Too many pub fails, resetting (x_x)");
resetSoftware();
}
delay(200);
}
}
}
// Signal distress if no messages are received in a while
if (millis() > last_sub + MAX_TIME_NO_MSG) {
Serial.println("No msgs received (╥_╥)");
for (int i = 0; i < 10; i++) {
digitalWrite(LED_BUILTIN, i % 2);
ledAnalogWrite(LEDC_CHANNEL_0, (brightness + 10.0f) * (i % 2));
delay(100);
}
last_sub = millis();
}
vTaskDelay(TICK_PERIOD);
tick++;
}
IoT Love Lantern
*PCBWay community is a sharing platform. We are not responsible for any design issues and parameter issues (board thickness, surface finish, etc.) you choose.
- Comments(0)
- Likes(1)
- (DIY) C64iSTANBUL Jun 03,2024
- 0 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
More by Carlos Asmat
-
-
-
kmMiniSchield MIDI I/O - IN/OUT/THROUGH MIDI extension for kmMidiMini
128 0 0 -
DIY Laser Power Meter with Arduino
190 0 2 -
-
-
Box & Bolt, 3D Printed Cardboard Crafting Tools
171 0 2 -