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_WIFI_SSID";
const char pass[] = "YOUR_WIFI_PASSWORD";
static const char ntpServerName[] = "us.pool.ntp.org";
const int timeZone = -8; // Los Angeles is UTC-8 (Pacific Standard Time)

#define TIMEZONE  -8
#define LATITUDE  34.0522
#define LONGITUDE -118.2437
#define LED_COUNT 24
#define LED_PIN   2
// ================================================================

WS2812FX ws2812fx(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
SunSet sun;
WiFiUDP Udp;
unsigned int localPort = 8888;
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];

time_t getNtpTime();
void sendNTPpacket(IPAddress &address);

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  setSyncInterval(300);

  sun.setPosition(LATITUDE, LONGITUDE, TIMEZONE);

  ws2812fx.init();
  ws2812fx.setBrightness(8); // Dim night light
  ws2812fx.setSpeed(40000);
  ws2812fx.setColor(0xFFB000); // Warm white/orange
  ws2812fx.setMode(FX_MODE_STATIC);
  ws2812fx.start();
}

void loop() {
  ws2812fx.service();

  sun.setCurrentDate(year(), month(), day());
  sun.setTZOffset(TIMEZONE);

  double sunrise = sun.calcSunrise(); // in minutes
  double sunset = sun.calcSunset();   // in minutes
  double time_rn = hour() * 60 + minute();

  bool isNight = (time_rn >= sunset || time_rn <= sunrise);

  if (isNight) {
    ws2812fx.setBrightness(8); // Dim night light
    ws2812fx.setColor(0xFFB000); // Warm white/orange
    ws2812fx.setMode(FX_MODE_STATIC);
    ws2812fx.service();
  } else {
    ws2812fx.setBrightness(0); // Off during the day
    ws2812fx.service();
  }

  delay(5000); // Check every 5 seconds
}

// ================== NTP & TIME HELPERS ==========================
time_t getNtpTime() {
  IPAddress ntpServerIP;
  while (Udp.parsePacket() > 0) ;
  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();
}