Tuesday, December 15, 2015

AutoPebble Programming: Eyes-Free Time Telling

I've always been fascinated with the challenge of being able to 'read' the current time without looking at a watch. Heck, why stop at the time, I'd love to be able to get all sorts of information from my devices without having to actually look at a physical device. I never did get a chance to buy this sweet braille watch from years ago, but now that I've got a hold of Shira's Pebble, I figured I could finally hack to together a solution.

Using AutoPebble, I'm able to send a vibration pattern to the watch which means that the Pebble can effectively talk Morse Code. At the core of my solution is this JavaScriptlet which maps text to a vibration pattern:

      function textToCode(text) {
        var code      = "";
        var letters   = text.toUpperCase().split("");
        var encoder   = {
          A: '.-',         B: '-...',       C: '-.-.',
          D: '-..',        E: '.',          F: '..-.',
          G: '--.',        H: '....',       I: '..',
          J: '.---',       K: '-.-',        L: '.-..',
          M: '--',         N: '-.',         O: '---',
          P: '.--.',       Q: '--.-',       R: '.-.',
          S: '...',        T: '-',          U: '..-',
          V: '...-',       W: '.--',        X: '-..-',
          Y: '-.--',       Z: '--..'
        };
        // Ben's Own Numeric Mapping
        encoder['1'] = encoder['A'];
        encoder['2'] = encoder['T'];
        encoder['3'] = encoder['H'];
        encoder['4'] = encoder['F'];
        encoder['5'] = encoder['V'];
        encoder['6'] = encoder['X'];
        encoder['7'] = encoder['S'];
        encoder['8'] = encoder['E'];
        encoder['9'] = encoder['N'];
        encoder['0'] = encoder['Z'];

        for(var i = 0; i < letters.length; i ++) {
          var c = letters[i];
          var e = encoder[c];
          if(e) {
            if(code != "") {
              code += " ";
            }
            code += e;
          }
        }
        return code;
      }

      function codeToPattern(code) {
        var code    = code.split('');
        var dot     = 250;
        var pattern = [];

        for(var i = 0; i < code.length; i++) {
          var letter = code[i];
          if(letter == ' ') {
            continue;
          } else if(letter == '.') {
            pattern.push(dot);
           } else if(letter == '-') {
            pattern.push(dot * 3);
          }
          var peek = (i + 1) == code.length ? null : code[i+1];
          if(peek == null) {
            continue;
          } else {
            pattern.push(peek == ' ' ? dot*7 : dot);
          }
        }
        return pattern.join(",");
      }
var text = local("par1");
var code = textToCode(text);
var pattern = codeToPattern(code);

There are a couple of hacks above worth noting. First off, each letter is being treated as its own word. So: Hello World would actually be sent as H E L L O W O R L D. For someone who struggles to read even the most basic Morse Code, this simplification makes sense. Maybe one day I'll graduate to parsing words.

Second of all, you'll notice that I'm not using the proper Morse Code for numbers. Instead, I'm using a mapping I made up. It's sort of logical: A = 1, as it's the first letter in the alphabet, 2 = T, as in Two, 3 = H as in tHree, and so on. I did this for a few reasons: first, Morse Code is optimized for frequently letters. So using A = 1 means that I can send 1 as • —. Had I used the proper Morse Code for 1, I'd have to send • — — — —. Secondly, if I'm going to manage to learn anything through this exercises, I'd prefer it was 10 different letters, rather than the Morse Code numbers.

Regardless, the above does the heavy lifting of converting text into dots and dashes, and from there into a Pebble vibration pattern. I wrap up the above code as an action:

Parse Morse (88)
A1: JavaScriptlet [ 
  Code: .. code from above ...
  Libraries: Auto Exit:On Timeout (Seconds):45 
]
A2: Return [
  Value:%%par2 Stop:On
]

Note that Parse Morse is an example of me figuring out how to make Tasker Actions far more modular. Parse Morse takes in two arguments: the first is the text to parse, and the second is the value to return (either code or pattern).

I then setup the Pebble Morse Time action to listen for requests from AutoPebble, invoke Parse Morse and then present the encoded time on the watch. Here's the code for this action:

Pebble Morse Time (106)
Abort Existing Task
A1: Perform Task [
  Name:Parse Morse
  Priority:%priority
  Parameter 1 (%par1):%TIME
  Parameter 2 (%par2):code
  Return Value Variable:%code
  Stop:Off
]
A2: Perform Task [
  Name:Parse Morse
  Priority:%priority
  Parameter 1 (%par1):%TIME
  Parameter 2 (%par2):pattern
  Return Value
  Variable:%pattern
  Stop:Off
]
A3: Variable Set [
  Name:%newline
  To:

  Do Maths:Off Append:Off
]
A4: Variable Search Replace [
  Variable:%code
  Search:  Ignore Case:Off
  Multi-Line:Off
  One Match Only:Off
  Store Matches In:%code
  Replace Matches:On
  Replace With:%newline
]
A5: AutoPebble Text Screen [
  Configuration:Full Screen: false
  Title: Time
  Text: %code
  Vibration Pattern: %pattern
]

The above action include string handling that turns spaces into newlines. I chose to do thiss via a Variable Search Replace action, though I'm beginning to appreciate that it may have been easier to just do this as a Javascriptlet. The multi-line approach me to render the Morse Code for the time in a large font, with one "letter" per line. Here's how it looks on the watch:

That's T Z Z Z O'Clock, or 20:00 or 8:00pm.

To polish off my no-eyes solution, I've setup two short-cuts. A long press opens up AutoPebble and another long press kicks off the Pebble Morse Time task.

It's a crude solution, but technically, it does work. I can manage to get the time buzzed to me all without ever looking at a physical device.

As for my ability to interpret Morse Code, I've still got a ways to go. For now, I'm both vibrating and showing the Morse Code of the time, and as you can tell above, the current time is included in the header of the watch itself. I find that most of the time I can properly interpret a digit or two from the vibration, and read most of the remaining digits by looking at dots and dashes.

All in all, it's a fun experiment and is just more proof at how cool AutoPebble is. It probably took longer to write up this blog post than did it to code up this solution. Good times.

No comments:

Post a Comment