Arduino
Smart Toilet WiFi Enabled Lights
This project demonstrates the design and implementation of a smart toilet lighting system using Arduino-compatible microcontrollers and electrical engineering principles. The system is engineered to address common challenges such as minimizing nighttime light discomfort, automating lighting based on environmental conditions, and optimizing energy efficiency. By integrating motion sensing, WiFi connectivity, and real-time clock synchronization, the solution provides adaptive illumination that responds intelligently to both user presence and natural light cycles.
The following guide assumes familiarity with the ESP8266 microcontroller and basic proficiency in uploading and verifying Arduino sketches. For a comprehensive introduction to the required hardware and setup, please refer to the WS2812B LED page.
Building upon the foundational LED control concepts, this project incorporates the HC-SR501 motion sensor with the ESP8266. The sensor's VCC, OUT, and GND pins are connected to the ESP8266's 3.3V rail, digital pin D7, and ground, respectively, completing the circuit for motion detection.
The next phase involves developing the embedded software to coordinate sensor input, time-based logic, and LED control. The code leverages several essential libraries for LED management, timekeeping, WiFi communication, and astronomical calculations for sunrise and sunset.
Package | Comment |
---|---|
WS2812FX.h | LED library for Arduino and ESP microcontrollers. |
TimeLib.h | Time management library for Arduino. |
ESP8266WiFi.h | ESP8266-specific WiFi routines library. |
WiFiUdp.h | Library for sending and receiving UDP packets. |
sunset.h | Library for sunrise and sunset calculations. |
The software architecture is modular and well-documented, with a particular emphasis on the main program loop where sensor data, time calculations, and lighting adjustments converge. The system dynamically adjusts LED brightness based on motion detection and ambient light, ensuring optimal user comfort and energy savings.
Below is the core Arduino code, annotated for clarity and maintainability. This implementation exemplifies best practices in embedded systems programming and electrical engineering integration.
#include WS2812FX.h
#include TimeLib.h
#include ESP8266WiFi.h
#include WiFiUdp.h
#include sunset.h
// =================== USER CONFIGURATION =========================
const char ssid[] = "YOUR_SSID_NAME";
const char pass[] = "YOUR_SSID_PWRD";
static const char ntpServerName[] = "YOUR_NTP_SERVER";
const int timeZone = YOUR_TIMEZONE;
#define TIMEZONE YOUR_TIMEZONE
#define LATITUDE YOUR_LAT_CORD
#define LONGITUDE YOUR_LONG_CORD
#define LED_COUNT YOUR_LED_COUNT
#define LED_PIN 2
#define TIMER_MS 5000
// ================================================================
constexpr int SENSOR_PIN = 13; // D7 on ESP8266
constexpr unsigned int LOCAL_PORT = 8888;
WS2812FX ws2812fx(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
SunSet sun;
WiFiUDP Udp;
time_t prevDisplay = 0;
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];
// Forward declarations
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);
void setup() {
Serial.begin(9600);
pinMode(SENSOR_PIN, INPUT);
delay(250);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("IP assigned: ");
Serial.println(WiFi.localIP());
Udp.begin(LOCAL_PORT);
Serial.print("UDP port: ");
Serial.println(Udp.localPort());
Serial.println("Waiting for NTP sync...");
setSyncProvider(getNtpTime);
setSyncInterval(300);
sun.setPosition(LATITUDE, LONGITUDE, TIMEZONE);
ws2812fx.init();
ws2812fx.setBrightness(8);
ws2812fx.setSpeed(40000);
ws2812fx.setColor(0xFF0000);
ws2812fx.setMode(FX_MODE_STATIC);
ws2812fx.start();
}
void loop() {
if (timeStatus() == timeSet && now() != prevDisplay) {
prevDisplay = now();
// Optionally display time
}
ws2812fx.service();
sun.setCurrentDate(year(), month(), day());
sun.setTZOffset(TIMEZONE);
double sunrise = sun.calcSunrise();
double sunsetTime = sun.calcSunset();
int currentMins = hour() * 60 + minute();
bool isNight = (currentMins >= sunsetTime) || (currentMins <= sunrise);
if (isNight) {
bool motion = digitalRead(SENSOR_PIN) == HIGH;
ws2812fx.setBrightness(motion ? 32 : 8);
ws2812fx.setColor(0xFF0000);
ws2812fx.setMode(FX_MODE_STATIC);
ws2812fx.service();
Serial.println(motion ? "Motion detected! - 32" : "Motion absent! - 8");
} else {
ws2812fx.setBrightness(0);
ws2812fx.setColor(0xFF0000);
ws2812fx.setMode(FX_MODE_STATIC);
ws2812fx.service();
Serial.println("light off");
}
delay(250);
}
// ================== NTP & TIME HELPERS ==========================
time_t getNtpTime() {
IPAddress ntpServerIP;
while (Udp.parsePacket() > 0) ; // discard any previously received packets
WiFi.hostByName(ntpServerName, ntpServerIP);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Udp.read(packetBuffer, NTP_PACKET_SIZE);
unsigned long secsSince1900 = (unsigned long)packetBuffer[40] << 24 |
(unsigned long)packetBuffer[41] << 16 |
(unsigned long)packetBuffer[42] << 8 |
(unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response :-(");
return 0;
}
void sendNTPpacket(IPAddress &address) {
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0b11100011;
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
Udp.beginPacket(address, 123);
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}