Today I made WALK UP! - The alarm clock that will walk you off the bed
Hi there! my name is Elad and I recently joined the crew here on Whatimade.today. I'm happy to be here and I hope you'll enjoy reading :)
I am an early riser and usually have no problem waking up in the morning. Yet sometimes, especially during long periods of not enough sleep, I find the everyday smartphone alarm clock isn't doing the trick... I just don't hear it. Another thing I noticed is that once I get off the bed and take a few steps - I'm good to go - its just getting to those few steps that may require... some special measures 🤔
I have a Garmin hand watch that's on me all the time, even when I sleep. MAYBE I could do something with it? I found the Connect IQ SDK and at first glance considered developing an application for my watch, only to later find out the specific model I'm using is not supported.
I went through a few other design alternatives, and eventually decided to create a hybrid of few of them: I will use my Garmin as a sensor, and build a "waking up mechanism" around it. I named the project " Walk Up! " and it took me a few evenings/nights to complete.
In this post I will briefly go through the moving parts of the project, and talk about the main features of each. This will not be a full code review, but an abstract overview. For the Full code, please refer to the Git repository.
The Alarm-clock side:
The Physical unit to actually play the the alarm consists of the following:
- ESP32
- Amplifier module (pam8403)
- 40mm loudspeaker.
- 0.96" OLED
This Unit is merely an alarm clock that can be turned on and off over MQTT. All the logic is implemented in the Python3 code that runs on the RPi.
To control the amplifier module and play sound I used XTronical's XT_DAC_Audio library. The library is generally great to use, but a bit hard to set up. I got it to work using an old version of the ESP32 board manager (V1.0.5) on the Arduino IDE. I could not get it to work properly on my usual PlatformIO over Visual Studio Code settings. A few hours of writing code without code-completion and proper syntax highlighting, and a few of tweaking the WAV file with Audacity and I had the speaker roaring my childhood's theme song (comment if you recognize it :D).
This was an interesting experience since I never tinkered with audio before. It was rather thought provoking too: two semesters ago I took a course in signal processing. One of the main themes in the course was the sampling error vs the quantization error tradeoff, the meaning and origin of the two and the mathematical means of minimizing them. Those ideas, Despite being fundamental (and rather simple, maybe) left a strong impression on me. When dealing with audio relying on MCUs and 8Bit mechanisms, adding to that the limited memory in the ESP, and those two mathematical objects hit you right in the face. In a good way though.
For the MQTT aspect of the code I used the popular PubSubClient library.
The OLED shows some messages, indicating the current state of the system.
The Raspberry Pi's side:
The Pi has a double role here really. First, it runs (constantly) the scheduling daemon that allows me to set new alarms anytime I wish, using my phone or laptop over my home network. Second, when the previously set alarm time comes, it runs the program that turns the ESP32-based alarm clock on, and then continuously polls Garmin's server to check whether the set number of steps is reached, turning the alarm off when it is. Let's dive deeper.
Alarm scheduling daemon:
The daemon is implemented in Python3 and mainly uses the time package, and the paho.MQTT module that is an MQTT driver for python. The Daemon "listens" for alarm requests (Over a dedicated MQTT Topic), and upon receiving a new alarm request, It invokes a Built-in scheduling mechanism in Linux to actually set the alarm-routine. I chose to use the already existing Linux's "at" utility (a less popular sibling of the Cron utility) as the actual scheduling mechanism. The main benefit is, well... that it's there already,and works well. Furthermore, it is reboot proof(thus power outage proof), and with it I can trigger any other program I wish, in any set time. The at utility is invoked from within the python code. I created a cron job for the daemon program, thus the Raspberry Pi invokes it right after booting.
Alarm-routine:
This is the program that actually triggers the alarm. As previously mentioned, it is invoked at the destined time and sends an "alarm_on" message to the ESP32 unit. After turning the alarm on, it continuously polls Garmin's servers using a dedicated API wrapper. This wrapper works flawlessly, and is worth checking if you have any Garmin device. It is simple and intuitive to use.
When the desired number of steps is reached-The routine sends "alarm_off", and exits.
Some images:
A video:
Final thoughts:
This one was fun. It was relatively quick to make and I gained some new skills and knowledge working on it. It is sub-optimal in some ways, mainly since I decided to utilize already-existing tools, at the expense of a simpler, minimalist architecture and fewer moving parts. Some future improvements I may add are on device alarm setting, alarm canceling ability, improved audio and maybe other "wake-up" goals: Rope jumping, Heart rate levels etc. All in all, I'm happy with the way it came out, and it definitely works- and that's what it's all about for me.
Thanks for reading.
Elad