Introduction (Motivation):
As
mentioned in previous articles (Such as this one about an Android-Based
Entertainment Center), I have long been on a quest for
something that should be simple. All I want is a Clock
that tells time. I want it to tell me the time; I
don't want to tell it the time -- not even once. I
certainly do not want to have it tell me the wrong time after
a power failure, or twice a year when the time changes to/from
Daylight Savings Time (DST).
It should also have basic functions like an alarm that can be
set to a schedule that people actually have -- like waking up
for work on weekdays, and sleeping in on Saturday and Sunday.
It should also have a usable user interface -- I don't want to
wait 60 seconds for it to "go around again" if I hold a button
an instant to long.
It should also have the "basics" like a readable display --
and it should look cool, too.
Mobile Phones, Tablets, PC's, and even some TV's (or Smart TV Boxes)
get their time from the network. We don't "set" them, and they
correctly follow DST. They also have convenient, sometimes
clever, user interfaces for setting alarm times, etc. Why shouldn't the
clock on our bureau/mantle/bed table work the same
way?
So I set out to look for such a device. To make an
already long introduction - long and not intolerable -- I
didn't find any.
Yes, there are so-called "Atomic Clocks". "Atomic
Clocks" (in the sense of a consumer item for the bedroom or
living room) -- aren't "Atomic" at all. This term
typically refers to clocks that attempt to receive a
signal from WWV -- a radio station run by the National
Institute of Standards. The problem is that there is only one
transmitter for this signal, and it is in Bolder,
Colorado. If you wanted to avoid a radio signal
from Bolder, Colorado,
your best bet would be to move to Maine or Florida. I happen
to live in that latter state. Getting a signal here is hit
or miss on the best WWV clocks. They also seem to only come
with simple, LCD displays that cannot be seen at night -- at
least not without pressing a button.
There are also some really cool-looking Nixie Tube clocks, and
yes, some of them have options for modules that allow them to
sync to GPS satellites. Again, assuming you sleep indoors,
getting a reliable GPS signal can be a problem. These clocks
also seem to cost upwards of 100 dollars, and that does not
include the GPS module. Even at well north of $100, they seem
to lack functions like alarms, and still have those piddly
little buttons.
Yes, I looked at others, too. Some claim to sync to signals
from local FM radio stations, others claim to be "factory
set". Where's that "Skeptical" emoticon when you need
it?
I had always had the idea of building my own cool-looking
Nixie or VFD clock. Then I happened across some hardware that
made my idea a possibility...
Back to Contents
Hardware:
Many years ago, I came across some (even at the time) old,
surplus, Alpha-Numeric, one-line, Vacuum Fluorescent Displays
(VFD's). Interestingly, and rater advanced for the time, they
accepted standard serial ASCII data as an input. I had
long-since sold that old VFD, but when I searched for Nixie/VFD
clocks, I thought of it. Then the "happenstance" --
A local surplus dealer had
several of these same VFD's. I made a deal with him for a number
of items, including one of the VFD's.
I took it home, and between some remembering, and looking up
pin-outs of some of the chips, I got it working. I went back to
the dealer, and told him that if he gave me another one, I would
write up a basic data sheet. He agreed. The
datasheet
can be found here, and the display I am talking about is
shown below:
20 Character by 1 line VFD.
More Technically, the displays are made by Noritake, and they
still use the "itron" brand in relation to the Dot Matrix VFD's
they make now. They seem to bear various part numbers, and there
also seem to be variations with different branding.
UPDATE: I have also obtained a 1 line, 40 character Dot
Matrix Display. I have a crude fork of my code for a 40
character display with upper/lower case. This code can be made
available upon request. See Google+, or Linuxslate forums
link below.
So I had my display -- a Cool, Retro-looking 13 Segment display
tube, Alpha-Numeric, and very easy to send data to.
But what do I drive it with? A Raspberry Pi is more power than
should be needed for an alarm clock, but Arduinos don't
typically have networking capability without adding "shields". I
was searching for WiFi modules for the Arduino when I learned
about something called
NodeMCU, and
the ESP8266 module that NodeMCU is based on.
NodeMCU looked like the perfect therapy for my Smart Clock
obsession. Built-in WiFi, Serial pins, and plenty of other pins
for things like PCM sound output. It also had GPIO that buttons
could be connected to, but a Smart Clock shouldn't have buttons.
NodeMCU also met all the other criteria. It has it's own
development tool, called "ESPlorer". ESPlorer is both simpler
and more elegant than the Arduino environment, and it is written
in Java, so installing it on Linux was trivial. Also
needed was a firmware loader called ESPTool. That uses
Python, so installing that on my Ubuntu Linux box was even --
"trivial-er"?
One last thing -- the actual NodeMCU development module costs
$6. -- and that was without shopping around. If you don't
impulsively click "Add to cart" on your favorite retailer, or if
you buy in quantity, you can find them for just over $3 each.
The NodeMCU Dev Kit is available
for only a few Dollars.
The only other thing I needed was a simple audio amplifier and
small speaker for the uploadable alarm tones. I went back to the
surplus dealer, and spent another $5 for the speaker assembly
from the bottom of a computer monitor. It contained a
USB-powered stereo amplifier, and 2 speakers. I wasn't planning
on stereo, and currently, NodeMCU only supports one PCM output,
so I cut off one speaker, and wired up the input that
corresponds to the remaining channel.
20 Digit VFD that is bigger, brighter, and cooler looking than
the $100 VFD clock kits? Check. Total cost: less
than $25.
Wiring it all up is almost literally a 5 minute job. Other than
power/GND, only 2 of the NodeMCU pins are needed.:
NodeMCU pin (Clock wise
from USB connector
|
Connected to
|
Vin
|
5V power To/from VFD power
pin, USB power cable, and the Audio Amplifier
|
GND
|
Audio Amp Ground
|
D2 (used as PCM out)
|
Audio Amp Signal
|
D10 (used as TX0)
|
VFD Serial Input
|
GND
|
VFD Serial Ground
|
At this point, a few
Electrical Caution Statements are
appropriate:
NodeMCU is
strictly a 3.3V device with the exception of
the 5V Power Input (Vin).
Do Not connect the VFD 5V
serial TX to NodeMCU's RX0 (D9) as damage will occur. Since D2
is an output, we can get away with connecting it to the VFD's
serial input without a level converter. The serial input will
accept anything over ~2.5V as a logic "1", so 3.3 volts works
fine.
Also, do not attempt to power the VFD using the Vin pin to
supply 5V from the USB connector on the NodeMCU Dev Kit. There
is a USB blocking diode that is meant to keep the 5V input from
backing up into the USB connector. Attempting to power the VFD
through the blocking diode will exceed it's current rating.
Lastly, the 3.3V D2 PCM output overpowers the line level (1V P-P
input) of the audio amp. Your amp needs to have a capacitively
coupled input, and some input attenuation (possibly in the form
of a volume control), or you need to build the
audio
filter shown in the documentation for the NodeMCU PCM function.
Back to Contents
Building and
Installing the Firmware on NodeMCU:
Like a lot of things in the geek world, the term "NodeMCU" is
used (correctly or not) to refer to several things. It can mean
the NodeMCU Dev Kit, which in itself is really just an ESP8266
"12E" module and a FTDI USB serial port soldered together, or it
can refer to the adaptation of Lua Script that is meant to run
on the aforementioned Dev Kit.
NodeMCU is not an "operating system". It is an Lua Script
Interpreter (written in C), customized for the ESP8266.
We need to build a custom version of NodeMCU. By far, the
easiest way to do this is by using the On-line
Automated Build Tool
that is run by a developer known as Frightanic. NodeMCU has very
limited RAM, and our Lua Script code will share this limited RAM
with the Lua Interpreter so it is vitally important to include
only the NodeMCU modules we really need.
Enter your email, Select ()Master<>, and then check
only
the following modules: end user setup, file, net, node,PCM,RTC
time,SNTP,timer, UART, and WiFi. (10 modules).
Click "Start your Build", and wait. When you get the download
links (check your spam folder), download only the
Integer
firmware image.
Given that you probably don't know what is on your NodeMCU Dev
Kit when you get it, I recommend doing a full chip erase.
This means that you will also need the
esp_init_data_default.bin
file from the current version of the
NodeMCU
SDK patch. Download the patch, and ignore everything
except that one file.
Follow
the instructions on the NodeMCU Flashing the firmware page
where it talks about using esptool.py. Do the
esptool.py
--port <serial-port-of-ESP8266> erase_flash
command
and the next line with
both
the integer firmware from the automated build
and the
esp_init_data_default.bin file.
esptool.py --port <serial-port-of-ESP8266> write_flash
-fm
dio
0x00000 <nodemcu-integer-firmware>.bin
0x3fc000
esp_init_data_default.bin
Power Cycle (not just reset) the NodeMCU after a successful
firmware flash.
Back to Contents
Software Design:
To address the issues mentioned in the introduction, My clock
had to meet several design criteria.
1. It had to display the correct time -- without
setting. This is easily accomplished with SNTP.
2. Since (1) requires an internet connection, why not have
the user interface be web-based -- Just like routers, switches,
and other "Internet of Things" (IoT) devices.
3. It should have selectable and changeable ring (alarm)
tones.
4. As mentioned it should have multiple alarms, and alarms
that can be set for weekdays, a single day, etc.
5. It should make use of the Alphanumeric capabilities of
the display. This includes Day and Date, as well as other
possibilities such as Weather, Stock Quotes, News Headlines,
etc.
Here is a screen grab of the main settings page:
Back to Contents
Limitations of
NodeMCU/ESP8266/Lua Script:
As mentioned, the entire computer that runs this -- with network
interface and all I/O -- is about the size of a large postage
stamp, and costs about $5. It is not a Octo core ARM device, or
even a Raspberry Pi. It has to have limits in it's capabilities,
and -- it does. It has 4 meg of flash storage in the form of a
simple, flat SPIFFS filesystem. It also has 128K of
memory, but even that is not all necessarily available to our
Lua program.
It has some other limitations -- the maximum amount of data that
can read or written from/to Flash in a single operation is 1K.
The maximum amount of data that can be sent over a single
network socket is 1460 Bytes. It's very easy to
instantiate a web server, but without some trickery we are only
ever going to serve very simple web pages. While it doesn't
specifically support CGI, we can implement simple GET and POST
operations.
Yes, we could do some fancier stuff with CSS, and perhaps some
Javascript, but serving that is going to take precious RAM from
our functional code.
Back to Contents
Code Walk-Thru:
NOTE: A Zip File of the Lua Scripts will be made
available as Open Source shortly.
UPDATE: Code Now Available
via
the Forum.
3 Simple and inexpensive modules: VFD, NodeMCU, and an Audio
Amp. Only 2 signal wires connecting them. The challenge is
obviously not in the hardware.
To save your time, I won't explain all of the code. Also,
it is not finished yet. (Is software ever finished?). I'll
go over the basic architecture, the start up sequence, and some
of the things the code needs to do to implement a viable clock.
This project was an excellent way to learn NodeMCU/Lua Script,
and much of my motivation for publishing this is to help others
learn.
NodeMCU Lua contains a simple, but powerful function called
enduser
setup that is specifically to allow NodeMCU IoT devices to
be easily linked to an existing WiFi network. A single command
creates a WiFi Access point which is running a Web Server that
allows us to find a WiFi base station, submit credentials, and
join. Show me another language that does that in one line.
When NodeMCU boots, it looks for a Lua Script called init.lua.
If present, it is executed. The documentation I read suggested
putting very little code in init.lua, and including a delay so
that in the case of an error, your NodeMCU is not stuck in a
boot loop. So in my implementation, init.lua simply waits 10
seconds (that is actually excessive), and then calls eus2.lua.
eus2.lua checks for a connection to a WiFi access point (AP),
and if there is none (in other words, an error connecting to
WiFi), it invokes the enduser setup function. If it is
assimilated, it simply displays the IP address, and kills off
the enduser setup server. If you leave EUS running, it
will continue to advertise itself as an access point even when
it is connected to the building WiFi.
eus2.lua in turn starts the actual clock (vfd_clock.lua).
As mentioned I will not explain the code line-by-line. Lua
Script is very simple, and very human - readable.
In short (and in order), vfd_clock.lua contains the following:
-- Initialization -- including simple "databases" (Lua "Tables",
which in this case are actually just arrays.) for:
The Names of the Days of
the Week
The Names of the Months
"Spring Forward" Dates for
the US through the year 2029
"Fall Back" Dates for the
US through the year 2029
Filenames for the
available ring tones -- Note that this should be automatic,
based on scanning the filesystem for properly encoded sound
files.
Defaults for things like
Time Zone (GMT offset), whether or not DST is used, etc.
Some of these should be read from a configuration file.
See Section below.
-- The Sound Player -- This is a slightly compressed/simplified
version of the example sound player code found with the PCM
module source code.
-- The Web Server -- Again, based on the example, but with
some little extras like a built-in 404 page. In the event of the
user accessing the Internet Settings page, control is passed to
another script that implements a dynamic web page that allows
the user to configure things like a Static IP address. In the
future, all of the settings pages may be handled in this
manner. At the very least, a dynamic page that displays
the current settings is needed.
-- A "Daytime" client -- From Sample code one the ESP8266 Forum.
This is currently only called once on boot, and only used to
determine if we are initially in DST or Standard Time. The
actual time retrieved is ignored for now.
-- The SNTP client -- Called initially and every hour to
maintain time sync. The ESP8266 real time clock (RTC) is
set to the time provided by the timeserver.
-- HTML POST code -- In essence, this is our CGI
processor. It retrieves the content of a HTML POST from
the web server, and processes the web forms. Currently, it also
saves the Alarm settings to a file so that if there is a power
interruption, or a reboot, the alarm settings will be
maintained. In the future, it should also save the basic clock
settings, including the selected display mode.
Alarm Settings Page - Settings are handled by a function
that is called when there is an HTML POST.
-- A timer function that runs once every second -- As you
can probably guess, this is the main functionality of the
clock. It has to do a number of things, including:
Determine what "Page" we
are on. With a one-line display, this means which line of text,
or message we are displaying.
Compute local time by
adding both the GMT offset, and the DST offset.
Check for Spring Forward,
or Fall Back, including handling things like the repeated hour
that happens each year on the "Fall Back" day.
Format the time for
each of the 4 (currently) possible displays:
24 Hour time with Clock only
12 Hour time with Clock only, including
things like the concept of 12AM (instead of 00hundred hours),
and AM or PM
24 Hour time with Day and Date
12 Hour time with Day and Date, including
things like the concept of 12AM (instead of 00hundred hours),
and AM or PM
Determine if there is a
sync or error message page, and display it.
Determine if there is
an alarm message page, and display it.
In the future, this may
include code to determine if we need to display a Weather
information page.
Check for someone pressing
"Alarm Cancel" or "Alarm Snooze". We need to check this
every second in order to respond in a timely manner.
-- A timer function for changing the display every 5 seconds
-- This allows us to alternate any alarm or error messages
on a 1 line display with the current time. In the future, this
may include Weather information.
-- A one minute timer function -- This checks for alarms,
and alarm time out, or snooze time out. Note that by doing
this every minute, instead of every second, we save processor
power, but it means that an alarm set for (for example) 07:00AM
will not sound until some number seconds into that minute.
An alarm can be at most 59 seconds late.
-- A one hour timer function -- Currently this is only used to
synchronize the RTC. In the future, this may include retrieving
Weather information.
-- Another, separate Lua script (inet_set.lua) -- This runs
anytime the user requests the internet settings page. This page
saves static IP settings. If DHCP is selected (default), the
static IP settings file is deleted.
Back to Contents
Current Status/Bugs/Issues:
The clock is currently working with Time or Time/Date display.
One Alarm is supported, and Alarm time/functionality is not lost
if there is a power outage or reboot. It is usable as an alarm
clock.
Please refer to the
NodeMCU
IoT Clock Status Update page, and the
NodeMCU
IoT Clock Source Code pages for the current issues list,
and updates.
Backto Contents
Conclusion:
The bright blue light, and clicking speaker still prevent me
from using this as my bed table alarm clock, but it is
functional, and with just a little more effort these 2 main
problems will be solved. Learning Lua script has been fun, and
Lua/NodeMCU is a great way to get into hardware/software
development. It's got the lowest barrier to entry of any
possible learning environment, even Arduino. Unless used simply
as an internet connection for a more powerful processor, it is
limited to relatively simple projects, but these projects are
not limited to IoT devices. NodeMCU would be a great way to
introduce children to programming, robotics, etc.
While I could certainly be accused of over-engineering something
as simple as an alarm clock, I really think there is a place in
the home for such a device. Today, peoples telephones are their
interface to everything, and going for your phone to silence
your bed side time display is not as far-out as it may have been
just a few years ago.
Back to Contents