Wake-up Ceiling Light




I like the idea of a wake-up light, simulating sunrise in the morning to wake up in a gentle fashion. There are many commercial products for this, usually having the form factor of a stand-alone bedside lamp. I thought the entire concept would actually work better if it were integrated into our bedroom's main ceiling lighting, so I decided to build that.

I started with the following requirements:

  1. The wake-up light should increase light intensity automatically from zero to full during a configurable period (for instance, starting at 6:30am ending up with full intensity at 7:00am).
  2. Normal functionality of the ceiling light (switching it on and off with the wall switch) must be retained; the wake-up functionality should just be an add-on to that.
  3. I wanted the solution to be integrated in the lamp; no additional visible boxes or cables.
  4. The solution must be stand-alone in the sense that it doesn't rely on any already deployed domotics system (for the simple reason that I don't have one).

Requirement (2) implies that the solution must be able to keep track of time and alarm settings with power-off. I've chosen NTP server synchronization for time sync and EEPROM storage for alarm settings. Requirements (1) and (3) imply that there must be some wireless way of configuring the alarm. I've chosen an HTML5 mobile app served by the lamp to implement this.


Step 1: Choosing the Light Fixture

This project starts with a regular ceiling lamp to modify. It has to be a LED-based lamp with a 12 Volt power supply module and LED unit inside. This set-up allows you to hook up your own electronics between the power supply and the LED unit. Of course, the fixture needs to have sufficient physical spare room for our electronics as well - about 8.0 x 5.0 x 3.0 cm (or 3.1 x 2.0 x 1.2 inch).

The super friendly guys at my local Hubo hardware store let me open up boxes to find a suitable one and I ended up with an Eglo LED GIRON 13493. This is a 24 LED, 12 Watt model. The picture shows this lamp in its unmodified form, with the cap removed. If you want to build this project with a bigger lamp, that's absolutely possible - the circuitry we'll use can handle much larger currents.

Costs for this particular ceiling lamp were €40 (about US$ 44).

Step 2: Other Parts and Equipment

I used the following electronics components in this project:

  • An LM2596 DC/DC step-down voltage regulator module (not just the LM2596 IC).
  • An ESP-01 module.
  • An LM358 opamp.
  • An STP65NF06 power MOSFET.
  • 7 Resistors: 5x 2k2, 1x 100k, 1x 220R
  • 2 Capacitors: 1x 100n, 1x 47n
  • 1 Diode: 1N4148

The MOSFET type is not critical. It just needs to be an N-Channel power MOSFET in TO-220 package with low on resistance - many other types will do.

The following connectors etc. are used to build the circuit:

  • 2 PCB screw terminals with 2 pins each (2.54mm / 0.1'') (for power supply and LED connections)
  • 1 male PCB header, 3 pins.(for optional serial port debug connection)
  • 1 female PCB header, 2 rows of 4 pins (we will plug the ESP-01 module into this)
  • A piece of prototype PCB with copper strips connecting 3 holes, like this.
  • A couple of pieces of mounting wire, preferably in a few different colors (for use on the PCB).
  • A piece of twin wire cable (for use between the power supply and our PCB).
  • 4 spacers/screws/bolts to firmly mount the PCB inside the lamp.
  • And of course some solder.

Total costs for the components vary a lot with the supplier. I think I paid about €15 (about US$ 16.50) for everything, but it should be possible to get a better deal through DX or AliExpress.

You'll need the following tools and equipment to build this:

  • Common tools like screwdrivers, a wire cutter and a wire stripper.
  • A soldering iron.
  • A drill with bits to drill in PCB and metal - I used a 3.0mm (0.12'') bit.
  • A voltage/multi meter.
  • A PC/Laptop with the Arduino IDE installed and the ability to program an ESP-01 module. This can be achieved by a regular USB-to-UART module in combination with some breadboard circuitry to put the ESP-01 in programming mode, or (which I think is more convenient) with an ESP-01 programming board (as pictured).
  • Although it's not strictly required, having an oscilloscope will come in handy if you need to debug the circuit.

Step 3: The Circuitry

Microcontroller core

The heart of the circuit is the ESP8266-based ESP-01 wifi microcontroller module. The basic idea is to program this thing to keep time, serve a webpage, trigger an alarm and control a dimmer, by sending a PWM signal to a MOSFET switch.

The ESP-01 board is cheap, small, and has an easy-to-use 2.54mm / 0.1'' pitch connector. The disadvantage is that you only get 2 general purpose input/output (GPIO) pins: GPIO0 and GPIO2. Also, both of these need to be pulled high initially for proper microcontroller start-up, and they are driven by the boot loader for a short while after start-up (as can be seen in the two attached scope screenshots). These things will lead to noticeable flicker if we would drive the lamp directly from either of those pins.

Looking at the scope measurements again, we can see that even during boot, there is no time when GPIO0 and GPIO2 are driven low simultaneously. We'll exploit this by constructing the circuit in such a way that the lamp will only turn on when both GPIO0 and GPIO2 are driven low - effectively putting a NOR gate between the GPIO0/2 and the MOSFET. GPIO0 will be used for (inverted) PWM, and GPIO2 will be an 'enable' pin. This set-up gives us full control to avoid flicker.

Opamp and MOSFET

The outputs of GPIO0 and GPIO2 are fed into the inverting input of the opamp via R4 and R5. The non-inverting input of the opamp gets a reference voltage of about 0.5V created by R6/D1. This sets up the desired NOR function. By feeding the opamp with 12V, it also provides the necessary boost from the 3.3V logic of the ESP-01 to the 10V+ required to fully drive the MOSFET. We drive the MOSFET from the opamp output through R7. While this certainly doesn't make an ideal MOSFET driver, it is absolutely good (fast) enough for this application. When building up the circuit on a breadboard I noticed some voltage spikes and ringing, probably related to the self inductance of the wires between the MOSFET and the LED unit. I (crudely but effectively) suppressed this by putting C2 over source and drain.

Power supply

Part of our circuit needs about 12V, and the other part needs about 3.3V, and we have an existing 12V power supply to get this from. We're effectively 'stealing' power from an existing design, hoping that the amount of power we draw doesn't exceed the safety margins in the existing lamp - which means we have to keep power usage pretty low.

According to this research, we need to assume a 215mA current draw from the ESP-01. Using a linear regulator (like an LD1117) is not a good option. It would mean that we would also draw the 215mA from the original power supply rated at 1A - so 215mA would be pretty significant. Also, the regulator would dissipate about 1.9W and thus need a heat sink. Therefore, I used a switching power supply module instead. This particular LM2596-based module can be adjusted to the desired 3.3V by adjusting a trimpot. Assuming a 85% conversion efficiency, it would draw 70mA from the original power supply and dissipate 125mW - which is much more acceptable.

Step 4: The PCB

I built up everything on a piece of prototype PCB board. I used the type that has copper strips connecting 3 holes as a matter of personal preference. I started by drilling 4 holes in the corners to be able to mount the board later, then soldered the main active components and socket for the ESP-01, then everything else.

Included are both a diagram of this PCB and photographs with and without the ESP-01 module plugged in. These together should provide all the needed info.

To connect the PCB, I used screw terminals for the power supply and LED unit connections, and a male print header to expose the serial port of the ESP-01. The latter is not required, but highly recommended to do debugging if necessary.

Step 5: The Software

If you want to use the software as-is without any modifications and don't care how it's made, the procedure is simple: download and unpack the attached 'wakeuplight_esp01.zip', open in the Arduino IDE. Modify the settings in 'configuration.h'. It needs your Wifi SSID and password, IP address information, the name of an NTP server (you can probably leave this unchanged), and timezone information - your standard offset from UTC in minutes as well as any daylight saving time rules.

After making the appropriate changes, simply upload the sketch to the ESP-01.

If you want to make some changes to the software, or simply are interested in how it works, some more detailed information is included below.

Overall architecture

My initial version of this software was in plain C and grew organically from experimenting. At some point, it worked (kinda), but it was a total mess. I then decided to refactor and switch to C++, creating a single class for each separate function (consisting of a .h file defining the class and a .cpp file containing the implementation). The classes get instantiated in the main module. Of course, most classes are dependent on others. The main module injects those dependencies through the constructors of the depending classes.

The following classes are present:

  • Configuration: provides an interface to all configuration data, both hardcoded (mentioned above) as well as data stored in EEPROM (like the alarm settings). All other modules (except Dimmer) depend on Configuration.
  • Dimmer: adjusts light intensity using PWM.
  • Wificlient: establishes the connection to a Wifi access point.
  • NTPClient: gets universal time from a time server.
  • LocalClock: converts universal time to local time, taking into account DST rules if any.
  • Alarm: uses Dimmer, LocalClock and Configuration to perform the basic function of switching on the light gradually during a set time period.
  • Webserver: serves a mobile-friendly web page to enable alarm configuration and manual control.
  • Serialhost: allows serial communication for debugging purposes.

More detailed information is available within the source files. The Dimmer and Webserver modules are special in the sense that they partly use generated code. The 'wakeuplight_java_helpers.zip' file contains an Eclipse Java project that does the generation. We'll zoom into this below.


The point of the wake-up light is to let the light intensity increase gradually as perceived by a human. The PWM mechanism gives us linear control over the light intensity, but human perception is more or less logarithmic (the Weber-Fechner law). If we wouldn't compensate for that and just let the PWM duty cycle increase from 0 to 100% in say 1000 steps, the result would be that in the early part of the wake-up cycle, light intensity would increase too fast with noticeable jumps, reaching a high level early, and then rise very slowly from high to full in the remainder of the cycle. That's obviously not what we want. We need to change the light intensity exponentially rather than linearly in time, to give the perception of a linear increase in time.

Also, the ESP8266 PWM is not perfect. It has some jitter which is noticeable in very small duty cycles and causes noticeable flicker in the lamp. So the light can be fully off, or at some minimum stable value, but we should avoid being in between. This problem becomes less severe if the PWM frequency is low - which is why I've chosen just 100Hz.

The file 'DutyCycle.java' calculates a function from a required step in perceived light intensity (on a 0 to 1800 scale) and a PWM value (on a 0 to 20000 scale). The 'ConvertDutyCycleToEsp.java' program calculates this function and writes it to a .h file to be included in the Arduino project. The Dimmer code in the Arduino simply does a look up on this generated table.


I wanted to control the project with my smartphone. As I have much more experience writing web-apps than native mobile apps, I decided to take the mobile-friendly web-app approach.

The web-app is a single-page HTML5/jQuery application that sends an Ajax POST request when the user presses a button (and also retrieves status updates periodically). The page instructs the browser to get jQuery from the jsDelivr CDN, all JavaScript and CSS code is included in the HTML, as well as the images using Data URLs. As a result, loading the page entails just a single GET request to the ESP-01, keeping everything simple and fast.

By including the 'mobile-web-app-capable' and 'apple-mobile-web-app-capable' tags and a shortcut icon link, smartphones can add this webpage to the home screen. After that, it can be started in the same way as an app (it will be started in a full screen browser), largely hiding the fact that it is not a native app.

Having to upload a sketch to the ESP-01 every time when testing small changes to the web page is not a nice development cycle. Therefore, I've developed this in a Java web project, with 'LightServlet.java' simulating the response of the ESP-01 to the Ajax POST requests. The 'ConvertWebpageToEsp.java' converts the web projects index.html to the 'webserver_homepage.h' include file which contains the web page as a string constant.

Step 6: Putting Everything Together

With the PCB built and the software uploaded to the ESP-01, it's time to put everything together.

To mount the PCB in the fixture, of course you need to drill some holes in it. I removed the power supply and LED unit prior to doing that, to avoid the drilling vibrations damaging them. After that, the PCB can be mounted using the spacers. I removed the original connecting wires from the power supply, and used them to connect to the PCB instead. I used a piece of twin wire to connect the PCB to the power supply. After this, the lamp could be mounted on the ceiling!

When switching on the lamp with the wall switch, the light should go fully on as usual, but with a short delay (much less than a second, but noticeable). You should now be able to point your mobile browser to the IP address of the lamp, and see the web page. With the 'Add to Home screen' option, you can add an icon to your home screen to start this as a true app (tested this on Android but should also work on iOS).

You can now configure the wake-up period and enable it. When you want to go to sleep, don't switch off the wall switch as the whole unit will lose power of course. Instead, press the 'off' button in the app. You will be gently woken up at the configured time the next morning.



    • Fandom Contest

      Fandom Contest
    • Colors of the Rainbow Contest

      Colors of the Rainbow Contest
    • Party Challenge

      Party Challenge

    21 Discussions


    Question 2 months ago

    Awesome project! Just what I was looking for to build a smart wake-up light.

    I built the circuit with few tweaks; translated the GUI to Finnish and added an external WiFi antenna to the ESP.

    I was wondering, is it possible to add an adjustable "auto-off" feature to the GUI? This would save the end-user from shutting the light off manually (I know, this is mega-lazy)


    1 year ago

    Awesome project.

    But I am little stuck , i am able to log on to the webserver but it says acquiring time and that is far as i am able to go.

    I have tried different NTP servers with no luck.

    Any ideas?

    1 reply

    Reply 1 year ago

    I had the same issue and found the problem was that the ntp client was not able to resolve the NTP server's name (probably some DNS issue). I set dynamicIP to true in configuration.h, which makes the ESP-01 get the network configuration via DHCP. You can set your router to assign the same IP address to your ESP so that you still know how to access the webpage.


    1 year ago

    Nice project. I bought the ceiling light with the same model number, but mine doesn't have an external power supply. The sticker says "13493 V4" instead of "13493 X"... Guess, I'll have to send it back...


    2 years ago

    Would it be difficult to add a skip on weekends button? Hard coded skip weekend logic is fine as well.

    I haven't had a chance to dig through the code too extensively but it compiles and I can access the web interface so that's considered a huge leap towards working. I just need to get the rest of the components (need that opamp).

    1 reply
    Frans van Buulawdark

    Reply 2 years ago

    Nice to hear that you're building the project! Hope it will all work out.

    By design, this lamp is only active as an alarm if you keep the wall switch on and switch off the lamp through the web interface. My wife and I simply keep the wall switch off during the weekend, so no need for anything special.

    Hardcoding weekend logic would be possible as well. Edit the file 'alarm.cpp'. In the alarm check logic, after "time_t localTime = localclock.getLocalTime();" you could do some additional checks. To prevent an alarm on Sunday (day 1) and Saturday (day 7) you could surround the alarm logic by something like "if( weekday(localTime) != 1 && weekDay(localTime) != 7) {"

    Making this configurable through a button is possible as well of course, but it would take changes at several places (HTML, webserver, configuration, alarm). Simply follow the patterns that are already there for other configurable things, like the alarm time.

    Really a inspiring project and very cleverly done with that NOR gate! As I'm not really satisfied with commercial wake-up lights (I'm the roll-over-and-snooze-on type), I'm looking to build a more imersive experience with some white LED strips and your circuit as a starting point. Just to be sure though: the smallest capacitors I have lying around are 4.7µf. I'm pretty sure I'll get away with that for C1, but do you think it would mess up the PWM signal when I increase C2 by a factor 100? I've been tinkering with electronics for a while now, but I'm still struggling a bit with these things.

    2 replies

    Hi Jeroen! Nice to hear that you like the project.

    I would recommend you buy some capacitors of the right capacity (it will set you back cents only).

    Looking at capacitor C1, there is theoretically no issue if the capacity would be higher. However, you need to take into account that practical capacitors are not ideal capacitors. 4.7uF and higher are usually electrolytic capacitors. These have a relatively large stray inductance, and that absolutely is a problem for a capacitor in this role. A 100nF ceramic capacitor doesn't have that issue - so go with that.

    For C2, you should't use a much bigger value than indicated.

    Thank you for the swift reply Frans! There's more to capacitors than capacitance and ESR apparently; I'll have a look into stray inductance. I ordered a bunch of ceramic capacitors and I'll keep you posted!


    3 years ago

    Love the project.. I have made a very very poor version of this with a full arduino board in the past but your project is FAR more sophisticated than mine. It also introduced me to the Esp8266, which is pretty awesome but Im a complete newb. First...when I try to compile your sketch i get an error that Timelib.h isnt there. Is it my IDE setup? Also, as a suggestion and something I was looking into doing with my project: Hack a couple amazon dash buttons to allow you to turn off the light without your phone. Also could be a multi step dimmer.

    4 replies
    Frans van BuulLeeW43

    Reply 3 years ago

    Hi Lee,
    Thanks for the compliments.
    As for the timelib: you have to install the time library (I actually should have mentioned that in the instructable.) In the Arduino IDE, go to Sketch -> Include Library -> Manage Libraries, then search and install "Time by Michael Margolis Version 1.5.0".
    I'll have a look at amazon dash buttons, never heard of them.

    LeeW43Frans van Buul

    Reply 3 years ago


    Ive run into major issues acquiring a lamp with a 12v power suppy. Everything Im finding at Home Depot, Menards, Lowe's has 36v, 96v.... and the things I find online dont tell you if there is a 12v power supply in them. HELP!

    Frans van BuulLeeW43

    Reply 3 years ago

    Hi Lee, sorry for a delayed response here. If you can't find one of these, there's not much I can do about it I'm afraid. The brand of my lamp is EGLO, maybe that will help.

    Otherwise, you could modify the schematic to support a higher voltage. One change you will need in that case is that the MOSFET driver stage around IC3 will need its owner power supply of around 10-12V rather than using the LED voltage directly.


    3 years ago

    The other improvement is security. The Web page the device presents should have an ID and login. This serves to protect your network, keep others from changing your wake up time and keeping multiple lamps from being confused. I want one in each bedroom, even the guest bedroom

    1 reply
    Frans van BuulSaulR11

    Reply 3 years ago

    Thanks for your suggestions! Funny thing: may daytime job is actually in the application security field, so I was very conscious of not including authentication/authorization. If you really want this, it's not too difficult to include it in the software. Personally I rely on the security of my home network and felt it was not necessary. If you're going to do it, you may also want to consider the connection security. I don't think the ESP-01 can serve an SSL-protected website, and password authentication without encrypted traffic is pretty useless.


    3 years ago

    Thank you A LOT for this awesome project!

    I have an esp lying around for this exact purpose for quite some time but haven't tackled the work yet. I will shamelessly steal your code now ;-)

    Again thanks for sharing!

    1 reply
    Frans van Buulploebb

    Reply 3 years ago

    That's really nice to hear, good luck building your version!


    3 years ago

    since your lamp is smart, the house power should be always on. Flipping the wall switch should send a signal to the lamp instead of power. This is important as someone might otherwise deposed the lamp. This can be accomplished in two ways: 1. In switch box, splice wire through. Pull low voltage wire pair from switch to lamp which will command the light on or off. Extra work to accept this must done at the controller. 2. Instead of pulling control wire, replace with wireless switch.


    3 years ago

    great instructable.