Atom Time
About
Let’s create a basic mini-app to set a time on the SB Watch with a numeric keyboard. The functionality will be similar you can achieve with the TimeSmith app, however, you can directly connect Atom and SB Watch and you will need no phone. This mini-app is called Atom Time.
Technically you only need Atom and an SB Watch, but this app supports PeekSmith 3 as well to display the time entered and to give you visual feedback about the time you set. If you have no PeekSmith connected, then it will be ignored.
We are sharing a basic version, and the source code of the built-in Atom Time mini-app.
Basic Version
Let’s start with a basic version. The advantage of this code is that it is shorter, and maybe easier to understand.
After uploading this code to Atom, theย main()
the function will be called and connect to your PeekSmith and SB Watch. As the device names are not specified, it will use the device names specified in the Settings (*
= any device by default). It will display “Atom Time” (\n
means a new line, so in two lines) on the PeekSmith as soon as it is connected.
There are three variables declared in the lines 8 – 15. The time
variable will contain the time you enter. The timeout
variable will contain a timeout variable, which is about sending the time entered after 4 seconds of the last key press. The mapping
contains the key mapping, what the keys mean.
The send()
function from line 18 is about sending the time to the watch. It is called when you press the bottom left button, or after 4 seconds. The 4 seconds timer (timeout
) is cleared to prevent calling the send function again. If the time
variable is an empty string, there’s nothing to send, so the code returns. If 4444
or 9999
was entered, it sets the current time, otherwise the time has been entered. Finally the time
variable will be cleared.
The onButtonClick
function is called with the button IDย (between 0 and 11, from top left to bottom right) pressed, and the first line maps it to a string that can be easier to understand than the button ID. If it is s
, then it immediately sends the time. If it is <
, then it deletes the last number of the time, otherwise it adds the number to the end of the time
string. Then it clears the timeout
timer, and set it to 4 seconds. Finally, it displays the actual time entered on the PeekSmith’s screen.
The function printFormattedTime
is about displaying the time going to be set on the watch. The second parameter is if the hands are moving, if it is true, then two stars will be displayed before and after the time.
And the onEvent
function is responsible for event handling. It cares about the hands started, hands finished and button click events, and calls the printFormattedTime
and onButtonClick
functions.
function main() {
ps.connect();
ps.print('Atom\nTime');
sbwatch.connect();
// sbwatch.setTime('12:00');
}
let time = ''; // the time entered
let timeout = 0; // will contain a timeout ID
let mapping = [ // button layour
'1', '2', '3',
'4', '5', '6',
'7', '8', '9',
's', '0', '<'
];
function send() {
clearTimeout(timeout); // don't trigger send
if (time === '') return; // nothing to set
if (time === '4444' || time === '9999') {
sbwatch.setCurrentTime();
} else {
sbwatch.setTime(time);
}
time = ''; // reset to empty string
}
function onButtonClick(buttonId) {
let key = mapping[buttonId];
// send immediately
if (key === 's') {
send();
return;
}
// delete the last number or add a new
if (key === '<') {
time = strSub(time, 0, -1);
} else {
time += key;
}
// delete the previous timer, and start a new with 4s
clearTimeout(timeout);
timeout = setTimeout(send, 4000);
// display the time entered
ps.print(`<${time}>`);
}
// displays the processed time, and hand movement indicator
function printFormattedTime(time, moving) {
if (moving) time = `*${time}*`;
ps.print(time);
}
// there are events coming from the SB Watch and the buttons of Atom
function onEvent(e) {
console.log(e.value, e.type, e.source);
if (e.source === 'sbwatch:hands' && e.type === 'started') {
atom.vibrate('\'');
printFormattedTime(e.value, true);
}
if (e.source === 'sbwatch:hands' && e.type === 'finished') {
atom.vibrate('\'');
printFormattedTime(e.value, false);
}
if (e.type === 'click' && e.source === 'atom:button') {
onButtonClick(parseInt(e.value));
}
}
Advanced Version (The Built-in Atom Time Mini-App)
Here’s the Atom Time code of the built-in mini-app. It supports several configuration settings (the timeout is not fix 4 seconds, if the time should be sent after entering the 4th number, if Pi Revelations information to be displayed), and a little bit “smarter”.
let time = ''; // the time entered
let lastTime = '';
let sent = false;
let timeout; // will contain a timeout
function main() {
ps.connect();
sbwatch.connect();
}
// Atom Time layout
const layout = [
'1', '2', '3',
'4', '5', '6',
'7', '8', '9',
's', '0', '<'
];
function printTimeEntered() {
let rest = '';
for (let i = strLen(time); i < 4; i++) {
rest += '_';
}
let text = `${time}${rest}\n`;
ps.print(text);
}
// displays the processed time, and hand movement indicator
function printFormattedTime(formatted, moving) {
if (moving) formatted = `*${formatted}*`;
const displayPi = config.get('atomtime.pi.display');
if (time === '' || !displayPi) {
ps.print(formatted);
return;
}
const piInfo = db.query("pi", parseInt(time));
for (let i = strLen(time); i < 4; i++) time = '0' + time;
ps.print(`${formatted}\n${time}\n${piInfo.page} ${piInfo.line} ${piInfo.across}`);
}
function send() {
clearTimeout(timeout); // don't trigger send
if (time === '') return; // nothing to set
if (time === '4444' || time === '9999') {
sbwatch.setCurrentTime();
time = '';
} else {
sbwatch.setTime(time);
}
sent = true; // will reset time to empty string
}
function onButtonClick(buttonId) {
if (sent) time = ''; // reset to empty string if already sent
sent = false;
const processAfterFourDigits = config.get('atomtime.submit.after_four_digits');
const key = layout[buttonId];
switch (key) {
case 's':
send();
lastTime = '';
return;
case '<':
if (time === '' && lastTime !== '') time = lastTime;
time = strSub(time, 0, -1);
break;
default:
if (strLen(time) < 4) {
time += key;
}
if (strLen(time) >= 4 && processAfterFourDigits) {
lastTime = time;
send();
return;
}
break;
}
// delete the previous timer, and start a new
clearTimeout(timeout);
const processAfter = config.get('keyboard.submit.after');
if (processAfter > 0) timeout = setTimeout(() => {
send();
lastTime = time;
}, processAfter);
// display the time entered
printTimeEntered();
}
function onButtonLongPress(buttonId) {
sbwatch.setCurrentTime();
time = '';
}
// there are events coming from the SB Watch and the buttons of Atom
function onEvent(e) {
if (e.source === 'ps:ble' && e.type === 'connected') {
ps.print('Atom\nTime');
setTimeout(printTimeEntered, 2000);
return;
}
if (e.source === 'sbwatch:hands') {
atom.vibrate('\'');
if (e.type === 'started') {
printFormattedTime(e.value, true);
}
if (e.type === 'finished') {
printFormattedTime(e.value, false);
}
}
if (e.source === 'atom:button') {
const buttonId = parseInt(e.value);
if (e.type === 'click') {
onButtonClick(buttonId);
}
if (strSub(e.type, 0, 5) === 'click' && strLen(e.type) === 6) {
const clickCount = parseInt(strCharAt(e.type, 5));
for (let i = 0; i < clickCount; i++) {
onButtonClick(buttonId);
}
}
if (e.type === 'longpress') {
onButtonLongPress(buttonId);
}
}
}
General
๐ย First Steps
MagiScript Editor
๐ย Basics
๐ย Running Your First Program
๐ย App Store
๐ย Atom Settings (Editor)
๐ย Debugging Techniques
Examples
๐ย Atom Time
๐๏ธ Time Practice
๐ย Atom Pi (Pi Revelations)
๐ย Atom Drum
๐๏ธ Atom Stack
๐ย Atom Square
๐ย Atom Level
๐ย Atom THMPR
๐ย Poker Hands
๐ย Keyboard Numeric
๐ย Keyboard NOKIA
๐ย Keyboard Cursor
๐ย Keyboard Media
๐ย Keyboard Custom
Input/Output
๐ย Buttons
๐ย Vibration Motor
๐ย RGB LED
๐ย Devices
๐ย PeekSmith
๐ย SB Watch
๐ย Bluetooth Keyboard
๐ย Bluetooth Mouse
๐ย Timers
๐ย Database
๐ย Events
๐ย System (exit, sleep, rand)
๐ย Objects (card, time)
Language
๐ย Summary
๐ย Comments
๐ย Variable Declarations
๐ย Operators
๐ย Control Flow
๐ย Functions
๐ย Numbers
๐ย Strings
๐ย Arrays
๐ย Objects
๐ย Uint8Array