An alarm clock for the rest of us

It’s a brand new year, which means I should really start writing a new post. I’ve been wanting to for a while, but we’ve been in lockdown for two months now and Google Analytics is the only indication that I’m not alone on the planet, and most of that is bots anyway. I’ve decided to take a page out of the book of my friend, James Stanley, who both does cool things and actually writes about them, so I’m starting to document all my projects again.

Given my non-frenetic, slow-paced lifestyle, I’ve long had a non-burning need. I don’t use an alarm to wake up, as I start work late, but I still want to know what time it is when I wake up, just to see if it’s way too early and I can go to sleep again. A few days a week I have tennis and need to get up early, but if it’s windy or rainy or very cold, the practice gets canceled and I want to know before I’m awake enough to not be able to go to sleep again.

To accommodate this lifestyle, I’ve traditionally turned to my mobile phone, but that has some disadvantages. Namely, the screen is too bright and wakes me up when I check the time, and I’m too obsessive to not check all my messages instead of falling asleep when I see the notifications on the screen. I’ve long thought that a bedside alarm clock would be perfect for me, but I couldn’t find one that fulfilled all my requirements:

  • I needed something that had a screen that would always be always lit, so I could check the time with one eye and half a brain awake, in the complete darkness of the bedroom.
  • A screen that wasn’t too bright and wouldn’t disturb sleep, but that would also be legible in direct sunlight, so I could see the time during the day. This meant adaptive brightness.
  • Octagonal shape so I can lay it down on its side (or at 45°) instead of having to crane my neck up to check the time when lying down (I really did think of everything).
  • Weather forecast for the next hour or two, so I can reliably fail to wake up for tennis when not necessary.
  • Annoying beeper for alarms.
  • Less annoying built-in LEDs that would increase in brighness for a few minutes before an alarm went off, so I can wake up less annoyed.

This is the result:

Look at this sexy thing.

Sexy.

Designing this thing

Conceptually, making an alarm clock to fulfill these requirements isn’t hard. You take a small OLED screen, an ESP8266, connect them together, add some LEDs and a buzzer, and you’re done! Since the hardware was more-or-less straightforward, I started with designing the octagonal case:

The back of the clock.

The OLED screen has four mounting holes, so I designed the mount around them. For the ESP8266, I use a WeMos D1 Mini board, as it’s quite small and nice to work with. I initially thought I’d have to connect the WeMos to the four pins of the screen with wires, but I discovered that if you kinda squint, you can get four of the ESP8266’s pins to match up with the screen’s pins and in the correct order, which means I could solder the ESP8266 behind the screen module directly, which simplified the wiring by a lot.

Look at that subtle off-white coloring.

While designing the clock, I created a quick mockup of the screen as I wanted it to show. I decided I wanted the hour to be displayed in as big letters as possible, since this screen is small, and the other elements I wanted were wind speed, temperature and weather forecast for the next hour.

The other components left to add were a photoresistor (for sensing ambient light), a buzzer and a LED strip. They were all straightforward to add, the resistor is connected to the ESP8266’s analog pin, and the buzzer and LED strip to some other free pins.

The software

The software was the slightly trickier part in this build, although that was pretty straightforward too. I needed multiple components:

  • Getting the time somehow (there’s no real-time clock on the ESP8266 and I didn’t want to add one).
  • Dimming the screen in a pleasing manner.
  • Getting the weather forecast and current weather.
  • Connecting to WiFi and autoupdating.
  • Annoying me into wakefulness in a satisfactory manner.

The clock

There’s an old Chinese saying:

To know the time, you must first connect to the internet.

– Sun Inc

Luckily, connecting to the Internet is very easy with tzapu’s excellent WiFiManager library. The clock creates an access point, you join it with your phone or computer, give it your WiFi network’s password, and you’re done.

After connecting, an NTP library can fetch the time every so often from the closest server, so the clock is always up to date. It was important to me that this clock is solid enough to trust with my most important wake-up alarms, and it achieves this goal admirably (unless the internet connection is down).

That also takes care of autoupdates, since I have a simple, secure autoupdate machine I set up using ESPOTA-server, an autoupdate server I wrote for the ESP8266. The clock checks for a new update every day, and automatically downloads and installs it. This way, distributing updates will work reliably, even to millions of devices, for when you realize that collecting all the users’ personal data is slightly monetizable.

The dimming

After a bit (or a lot) of searching, I finally found how to dim the OLED screen, and another important feature was well on the way of being implemented. Because it was rather hard to find, I’ll post the code here, along with the appropriate SEO keyword for people to be able to find it. Here is the code for dimming an SSD1306-compatible, I2C 128x64 OLED screen:

void brightnessTask(int brightness) {
    // Set the brightness of the SSD1306 OLED screen with this hack.
    // From https:/www.youtube.com/watch?v=hFpXfSnDNSY.
    // `brightness` should be a value between 5 (for some reason) and 255.
    display.ssd1306_command(SSD1306_SETCONTRAST); //0x81
    display.ssd1306_command(brightness);

    display.ssd1306_command(SSD1306_SETPRECHARGE); //0xD9
    display.ssd1306_command(0);

    display.ssd1306_command(SSD1306_SETVCOMDETECT); //0xDB
    display.ssd1306_command(0);
}

Once I discovered that, the rest of the dimming was easy: I would just read the ambient light from the photoresistor and set the screen’s brightness according to the photoresistor’s value.

Another job well done.

The weather

What a beauty.

Getting the weather was easier than I thought. OpenWeather has a simple API, which accepts a pair of coordinates and gives you the current weather and forecast for that location. It only took a few minutes to fetch that data on the clock, and then I spent some time positioning them on the screen and turning the forecast into an appropriate icon so it could be displayed on the small screen.

To display the icons, I used Adafruit’s always helpful GFX library and converted the OpenWeather icons to a format more suitable for display on a monochrome screen. This took a bit of trial and error, as I wanted the icons to be easily distinguishable at a glance, even though their size was 12x12 pixels and just one color. In the end, I think they worked out well, as it’s easy to tell if it’s raining or not.

The wakefulness

So the initial plan here was to have a buzzer buzz loudly and annoyingly in an attempt to wake me up. However, I am a pretty light sleeper, and I hate loud and annoying sounds (surprisingly), so I wanted this to be a last resort. The solution I came up with here is the following:

Say I want to set the alarm for 9:30, just in time to be ten minutes late for tennis. The LEDs would start glowing very faintly at 9:20, slowly increasing in intensity over the next ten minutes, at which point they’d reach maximum. If I still wasn’t up by then, the buzzer would begin beeping at the top of its lung, hopefully waking me up reliably. This seemed like a pretty good algorithm, and one that would both wake me up pleasantly and reliably.

There was only one problem: The clock doesn’t have any buttons or controls or any way for me to enter the alarm time. I could create a web server where I could configure alarms, but I figured I’d rather get a rooster instead, so I did neither and just made an alarm clock that cannot alarm. This symbolizes the futility of human existence and its incessant search for meaning in a cold and unfeeling universe that’s ultimately profoundly devoid of such, and then you die.

Not having to wake up to a buzzer is cool, though.

Epilogue

Overall, I’m pretty happy with this clock! I can now open an eyelid, look at the time and fall asleep again, which is a massive quality-of-life improvement over the previous “fuck sleep I’ve got Instagram likes” situation. The octagonal shape is a killer feature, I keep the clock angled 45° (as in the photo) and it really is the perfect angle for reading it while lying down.

One thing I’d like to improve in the future is to add a battery, because right now it’s solely USB powered and will obviously die if there’s a power outage. Adding a small LiPo battery and a charger circuit will be pretty easy and will ensure that the clock can keep running for hours even without power.

The source code is here:

https://gitlab.com/stavros/do-not-be-alarmed

It’s not very complete, so use it at your own risk, and I haven’t really added deployment details, but it should be very easy to build with one PlatformIO command.

As always, you can tweet or toot at me, or email me directly for any feedback/hate mail.