Sunday, March 25, 2018, 08:12
Posted by Administrator
I have been using my minimalistic Pi Zero W flasher clock for a while now and have found it to be an exceptionally soothing way to check on the current time. I recently ported the code over to work on the Pi 3 B+ and have edited my previous post about it to include both versions.Posted by Administrator
The only trouble with this clock has been that the code for it is very specifically for a Raspberry Pi, and I have found myself wanting to have a flashing clock indicator like this on other devices like phones, televisions, etc. Clearly, the flasher clock I designed was in need of another port, so set of to re-create it in Javascript.
It was a much more interesting challenge to get this working in Javascript than I expected it to be since Javascript is non-blocking and there is no built-in way to pause execution and sleep as you can with bash scripting. However, with some new features that most modern browsers take advantage of, Javascript is now capable of handling asynchronous functions natively and can use the async/await keywords to sort of hold off on execution until a promise for the await returns.
With async/await and promises, I was able to create a helper function to simulate a similar sleep behavior that my original script had without having to re-design everything to work as a weird sort of state machine using setTimeouts. This new code could have certainly be re-written to not use async/await but I believe it would be a lot less straightforward to make sense of that way. I was also able to take advantage of another ES6 addition, arrow functions, to streamline this custom wait function into the following one-liner:
var wait = t => new Promise(resolve => setTimeout(() => resolve(), t));
This function, wait, takes a variable t which is the time in milliseconds that the setTimeout should wait until returning a promise. With this component in place I had everything I needed to finish up converting my original design into something that could run in any modern browser:
<html>
<head>
<title>Javascript Flasher Clock</title>
<script>
// Set up our colors array
const colors = [
'#FFFFFF',
'#FF0000',
'#FF8000',
'#FFFF00',
'#80FF00',
'#00FF00',
'#00FF80',
'#00FFFF',
'#0080FF',
'#0000FF',
'#7F00FF',
'#FF00FF',
'#FF007F'
];
// Set up our default color index
var c = 0;
// Set up our base wait time
var w = 50;
// Define the wait function, a promise that waits for a setTimeout of length t before returning
var wait = t => new Promise(resolve => setTimeout(() => resolve(), t));
// A function to change the color
function changeColor() {
// If we are at the end of the colors array set c back to the first value
if ( c === colors.length - 1) {
// Set c back to the first color
c = 0;
}
// Else we just need to increment our color value c
else {
// Increment c
c++;
}
}
// Define our clock function using async so that we can use await
async function clock() {
// Set the default background color to black at the beginning of each cycle
document.body.style.background = '#000000';
// Wait for a long while so that we separate our flasher clock cycles
await wait(w * 40);
// Get the current date
let date = new Date();
// Get the current number of hours
let hours = ((date.getHours() + 11) % 12 + 1);
// Get the current number of tens digits
let tensDigits = (date.getMinutes() < 10 ? '0' : '' + date.getMinutes()).substring(1,0);
// Flash the current number of hours
for (let h = 0; h < hours; h++) {
// Wait a while
await wait(w*8);
// Set the screen to the colors c value
document.body.style.background = colors[c];
// Wait another while
await wait(w*8);
// Set the screen back to black
document.body.style.background = '#000000';
}
// Wait a medium while between the hours and tens digits flashes
await wait(w*20);
// Flash for the current number of tens digits
for (let t = 0; t < tensDigits; t++) {
// Wait a little while
await wait(w*5);
// Set the screen to the colors c value
document.body.style.background = colors[c];
// Wait another little while
await wait(w*5);
// Set the screen back to black
document.body.style.background = '#000000';
}
// Call this clock function again to start a new cycle
clock();
}
</script>
</head>
<body onload='clock()' onclick='changeColor()'>
</body>
</html>
I also added the capability to click anywhere on the screen to cycle through many different color codes so that the one can switch up the display color of the flash easily even if using a phone.
As with the original design, the clock flashes for the current number of hours ( in 12-hour format ) and then flashes a little more quickly once for every current tens digit of minutes. For example, if the time is 6:38 the clock will flash 6 times somewhat slowly, and then three times somewhat faster. I decided that the clock should be in 12-hour format in order to cut down on the number of flashes one would potentially have to watch in each cycle. Similarly, I have foregone the full number of minutes to cut down on the number of flashes one would have to count. Staying within ten minutes of accuracy seems like a good compromise between the time necessary to read the clock and precision to me.
The Javascript Flasher Clock can be experienced here.
I'm very happy with the results. It was great to finally make use some of the newest additions to Javascript. These new features made it possible for me to rewrite my original script much more easily than I had originally imagined.
My plan is to shine a phone running this clock at a wall so that the whole wall is a time indicator, but I'm also interested in lighting up translucent objects so that the object itself can be the time indicator. A milk jug should work great for that, although it may look classier inside of a paper lantern.
-- Addendum, March 26 2018
I have found a nice opaque white container that diffuses a phones display well and have placed it in the middle of my indoor sand garden. The phone is able to remain charged by keeping it plugged in with a hole for the cord I made in the back of the container. It then struck me that I had no way to change the light color or intensity once everything was assembled in the jar, but this was easily solved by adding Teamviewer Host to the phone and the remotely controlling phone from another device to change the display brightness or cycle through color options.
add comment
( 2617 views )
| permalink
| ( 2.9 / 4438 )