foote.pub

Jonathan Foote, Security Dad

Follow Me On

GitHub Open source code

Twitter Mostly retweets and non-sequitors

 

Posts

Stowing distracting MacOS apps (personal edition)

Stowing distracting Android apps

Other

Quantifying time spent unplugged


Unplugging

… can be lame

Intentionally disconnecting oneself from the internet seems to be a polarizing topic. TIL there is a “National Day of Unplugging.”. It looks like some (many?) people who participate in this event take selfies of what they are doing when they are offline so they can later post them to the internet. Hmm… maybe they are doing it wrong. Anyway, in addition to that viral/Facebook-style event, there are loads of blog posts citing counter points, many articles floating around Silicon Valley about the importance of vacation, countless articles on using mobile devices to stay connected at all times, and so on. So, there are pointed opinions on the subject.

Unplug sign

… but it can be rad

I’d prefer to stay out of all that. It suffices to say that I embrace technology and think it is pretty cool. But, while it may seem counterintuitive, including daily and weekly unplugging as part of my M.O. has significantly (and across the board):

  • Increased my focus
  • Lowered my anxiety
  • Reduced my tendency to over-work
  • Re-enabled my ability to enjoy playing tabletop board games and similar activities (odd, but true)

I’ve noticed that “unplugging” itself doesn’t really change anything for me. In order to get any benefit I have to let go of work, news feeds, self-imposed expectations, etc. If I get off my devices and then worry about stuff I’m not much further ahead than if I just continued hacking and compulsively keeping up with events on my smartphone. So while unplugging doesn’t inherently gear me up for improved focus and lower anxiety, I’ve found that time spent completely AFK does loosely correlate with the benefits listed above.

Quantifying time spent in Analog

OK, enough crap. On to the technical details.

As part of an experiment to play with git-shadow, I developed a system for tracking how much time I am unplugged each day. The result isn’t unlike other “quantified self” apps and systems, but the funny thing is that rather than encouraging me to compulsively check my progress, I find I am encouraged to relax and do something else. Note that there is an existing iOS app that tracks iPhone usage, but that this idea is a bit different.

<— see the ‘A/D Balance’ sidebar for a demo

In the remainder of this blog post I’ll cover the design of this system, which I am currently calling unplug due to a sheer lack of creativity, and some initial results.

System Design

This section covers the design of the system.

Goals

Venn

I don’t have expectations for this system to come into any kind of widespread use, but I did keep a few loose goals in mind as I hacked it together:

  • Users' data should belong to them and be completely under their control

    • It should use no app-specific server infrastructure
    • It shouldn’t require any new credentials or accounts in general
  • Keep “unplugged” time calculation simple

    • Use set logic: unplugged_time = all_time - union_of_time_on_each_device
  • Keep the design open to new device types and tracking methods

  • Make each device daemon and passive as possible

    • Device daemons should only need to report time that they are active, when they can, respectively
    • The system should degrade gracefully with delayed updates from each daemon
  • Results are published to the web

    • I knew I wanted to make something like that badge over in the sidebar as a PoC :)

Components

After reading a bit, I deciced to break the system into the following top-level components

Top-level Data Flow

While I only coded up apps for OSX and Android, any device OS that has decent input APIs and support for one of the Google Spreadsheets libraries would work.

The following sections briefly describe each component.

OSX Daemon

This is the first bit I coded. It is a simple python script controlled by LaunchDaemon. For my Macbook, I figured device input (keyboard, trackpad, whatever) is a good proxy for device usage, so the script simply polls ioreg for the last device input time and updates it’s activity table accordingly.

Android App

This is the 3rd bit I coded, after getting an initial POC using the OSX Daemon and Storage components working. While ideally I would use the same heuristic as the OSX Daemon (user input – screen touches in this case) to track device usage, it was a lot easier to use a combo of whether the screen is on and the keyguard is active. And it seems to work pretty well, for how I use my smartphone at least. So, this app uses a few BroadcastReceivers to catch system events (and re-install themselves when the device reboots) along with a polling loop that updates the device’s activity table.

Storage

I actually did this part twice. My first attempt simply used a JSON file stored in Google Drive, but serving JSON data for multiple devices over the web (while adhering to the “no server infrastructure” goal above) was problematic. So I migrated to using a Google Spreadsheet, which conveniently supports multiple devices (one per sheet) and Google will handily serve via JSONP. The key aspects of the Spreadsheet usage are:

  • Each device uses Google OAuth to get write access to the Spreadsheet, so the user doesn’t have to create a new account (assuming they have a Google Account)
  • If the spreadsheet doesn’t exist, the first device to write to it creates it and enables serving its contents to websites as JSON
  • Each device gets a worksheet (a tab) in the spreadsheet
  • Each worksheet has two columns: the time a usage of the device started and the time the usage stopped
  • And of course, the Spreadsheet constitutes all of the data stored by the system, and it is stored in the respective user’s account so they have total control over it

So the data store behind the system is simply a spreadsheet, no different than the one most people use to keep track of their passwords ;). For example, here is the Spreadsheet that contains my device usage data:

I think this design is pretty simple and understandable. The only major downside is speed. Obviously the data could be normalized for presentation, and Google Spreadsheets are served kinda slow at times (note: a quick web search will reveal many workarounds).

Web

As mentioned above, using Google Spreadsheets allows device activity to be served over the web as JSON, so consumption is pretty much open to any web technology. For my PoC though, this is what happens:

  1. The Spreadsheet data is loaded via Tabletop.js
  2. The entries in the spreadsheet are coalesced into a single list of per-device events
  3. The list is analyzed to slice the time period by which devices were active, including set logic to determine ‘unplugged’ time
  4. The result is passed to a text generator and a Google Chart for display

I’ve wrapped all of the above into a rough-but-flexible Javascript library that allows for slicing data by days, an arbtriary number of devices, etc. As of this writing the sidebar on the left displays usage data sliced by day, but it could be sliced by week, displayed as a histogram, and probably used for a lot of other analysis. I am no data scientist. Anyway, here is an example using the existing code to show a week’s worth of data in a div called “example”:

    <div id="example"></div>

    <script src="http://foote.pub/scripts/unplug/jquery.js"></script>
    <script src="http://foote.pub/scripts/unplug/tabletop.js"></script>
    <script src="http://foote.pub/scripts/unplug/moment.js"></script>
    <script src="http://foote.pub/scripts/unplug/unplug.js"></script>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>

    <script type="text/javascript">
      var spreadsheet_id = '1QOPqFo1RQFrnyFGbvvNkU_JFeoWV8KYCiLR1jVOZ1nI';

      function drawGoogleChart(events, usage) {

         // 3. Draw the Google Chart

         var options = {
           width: 300,
           height: 300,
           legend: { position: 'none' },
           bar: { groupWidth: '75%' },
           isStacked: true,
           hAxis: { textPosition: 'none' },
           vAxis: { textPosition: 'none' },
         };

         var data = unplugged.getGoogleDataTable(events, usage, 7);
         var chart = new google.visualization.ColumnChart(document.getElementById('example'));
         chart.draw(data, options);
      }

      function showInfo(events) {

        // 2. Get stats and pass them to a Google Charts callback

        usage = unplugged.getAllUsage(events);
        google.load('visualization', '1.0', {'packages':['corechart'], 'callback' : 'drawGoogleChart(' + JSON.stringify(events) + ',' + JSON.stringify(usage) + ')'});
      }

    // 1. Get activity data from spreadsheet and call showInfo when it loads

    data = unplugged.getData(spreadsheet_id, showInfo);
    </script>

As I mentioned the Javascript is a bit rough, but the idea is the user would specifiy spreadsheet_id, [1] call getData with it, then [2] do whatever they want with the data in the callback. For example, the getUsage function calcuates some useful stats for display, and getSummaryText gets a message that says how long the user has been unplugged, and since when. Anyway, in this example the stats are [3] passed to the getGoogleDataTable function, which generates an object that is passed directly into a Google Chart constructor.

What’s Next

I think tracking this data is kinda cool, but whether or not I polish and publish the code will depend largely on what others think of it.

I might clean up and open source the code, add some more platforms, or do all those things plus make installable apps. I’ve also been noodling the idea of taking the Google Spreadsheets publication chunk (which was kind of a pain to figure out as the official support for the Google Spreadsheet API is pretty weak) and making it into a standalone app. Publishing metrics from the commandline to the web in near-real-time without giving it up to another company could be as easy as my_monitor | publish_to_spreadsheet locally and getData(spreadsheet_id) in your Javascript.

But, that is all tentative. The real reason I jumped into this was to gather data that I can use with git-shadow. I’ve already started tinkering with it to get some cool results, but it will be a little while before I’ll have bandwidth to do a full analysis so you’ll have to stay tuned for that.

Teaser

Teaser: git-shadow provides a definitive answer to the question "How long did it take you to code that?"

Anyway, thanks for reading. If you’re interested in using this system, want the code, or have some feedback on the subject feel free to comment below, email me, or otherwise get in touch.

OK, time to unplug for the day :)