A personal project I recently completed reminded me of a movie quote by another engineer:
Damage control is easy. Reading Klingon; that’s hard. — Chief Engineer Scotty in Star Trek IV: The Voyage Home
Technology is easy. Designing a good user experience; that’s hard. — Me
Writing, Distraction Free
Few months ago I read an article about a new product named FreeWrite designed for distraction-free writing. That product intrigued me because I have a college-bound son who could benefit from such a product. The only trouble was the $549 price tag that seemed excessive considering its limited features. Granted, that is the whole point of the product yet I felt confident that I could build something equivalent for far lower cost. I am pleased to report that after investing only about $75 and some of my spare time, the finished product turned out quite nicely and became a very nice parting gift to my son for his journey into creative writing.
First, I sketched out some basic requirements to validate my design choices, prioritize the development work and to ward off feature creep. I only had a month before my son left for college.
- It must survive a college dorm or at least be cheap enough to not worry too much.
- It must be compact enough to easily transport to college and back, yet offer a display and keyboard bigger and better than a mobile phone.
- It must support choice of full-size ergonomic keyboard (quaint as they may be). Mouse should be optional, especially if the device already has a touch screen.
- No email, chat, messenger, SMS, etc.
- No way for a quick peek of YouTube, Facebook, Instagram, etc.
- KISS, YAGNI and minimalistic: focus purely on the writing plain text, not on fiddling with formatting like fonts, colors, line spacing, paragraph indents, etc.
- It must not require network connection for normal operation.
- It must be able to export the documents to a USB flash drive or other portable storage devices.
- It must automatically save document periodically to avoid loss of data in case of power outage or accidents.
- It should be secured against unauthorized use (the evil maid — or roommate — attack).
- It should be able to run on battery power.
- It should support both wired and wireless networking, if available.
- It should support tethering to a mobile phone hotspot.
- It should be able to send documents over email service like Gmail.
- It should be able to save documents to cloud services such as Google Drive, Dropbox, or Amazon Cloud Drive.
- It should offer at least some entertainment for a homesick college kid: music and/or photos, perhaps.
- It should offer some way to adjust text size.
- It should be easy to update/extend, though requiring a visit to the “shop” can be handy excuse to have son visit home every now and then.
- It should record time spent actually writing, and provide a summary view.
Before diving into the technical implementation details, let’s take a quick tour of the features.
You can create any number of user accounts, secured by passwords.
Private and Shared Documents
If you’re logged on, you can only see your own documents. If you are logged out, you will only see the shared documents. You can delete documents, or lock them against accidental overwrite or deletion. There are no folders or other document management features, so to copy a file you simply open it and save it with a different name or to a different storage location (or different user account, for that matter).
You can choose the font and text size used to display the document. You can also adjust the autosave frequency, lock screen timeout and slideshow, and so on. The settings are stored in each user’s account. The autosave feature by default saves the document under a temporary name rather than the original document same, providing a crude one level version history until you save the document.
USB Storage Devices
The default storage location for the documents is the internal storage of the device. The capacity is roughly the size of the MicroSD card used for the system software: I used a grossly over-sized 64GB card, leaving about 55GB for documents. However, you can plug in USB storage devices and select any one of them as the storage for all subsequent documents. Shown here is a single 16GB USB flash drive I had named BLUE_BRICK because it is in fact a blue LEGO 2x4 stud brick.
Wired and Wireless Networking
You can see how (if at all) the device is connected to networks, including mobile phone hotspots. This is showing a wired network connection, and an inactive wireless network.
You can connect to a nearby wireless networks, including mobile hotspots, provided you know the password (if secured). You can disconnect (or forget) previously connected wireless networks as well. The list refreshes automatically every 15 seconds.
Send via Gmail
You can send documents via Gmail to anyone else. The sender must be on Gmail but the recipient can be anyone. The default is to send the document to yourself, in case you wanted to edit on another device.
The device will automatically start a slideshow after a configurable idle time, showing a random set of photos from any of the sets available. There are several sets of photos harvested from https://www.pexels.com but you can extend those sets or create your own by storing photos on a connected USB flash drive in a folder named slides. I scaled the pre-defined sets of photos to 800x480 to match the display I happened to use.
The remainder of this article provides a deeper dive into how the technology under the hood. If you are not into that level of geekiness, feel free to TL;DR the rest of this.
Choices, Choices, Choices
I think Steve Jobs and Mark Zuckerberg do have a point in their wardrobe choices. The trouble with having a lifetime of engineering experience is that I could easily think of far too many different ways I could implement this product. I am a full-stack developer in the (no pun intended) full sense of that word: I can build a product like this literally from the bare metal all the way up to the user interface. The most immediate goal, therefore, was picking the best path forward in the limited time I had available. That’s where those requirements listed above come in handy, though they did not help much in my struggle to come up with a good user interface design. That took by far the longest time.
The first design choice was the hardware platform: build it from an existing device such as a laptop or tablet, or build it from a do-it-yourself platform like a Raspberry Pi. That decision turned out to be relatively quick and easy: even after adding few more essential parts, the cost of Raspberry Pi ($35) based device is hard to beat. Besides, I was not particularly keen on trying out yet another cheap laptop given how many of them already litter our e-waste junk pile. I also ruled out buying some cheap Android tablet only to waste much of my time gutting it (i.e. turning off all the unnecessary distractions).
Having settled on a hardware platform, I initially thought I might just cobble together a software solution starting from any one of dozen open-source text editors. That would certainly suffice for the actual task of writing. However, I quickly concluded that the operative phrase here is cobble together: starting out that way would likely result in an ill-fitting fragile system overall, typical of forced integrations of dissimilar products. In engineering-speak we often call that a kludge, or Google+.
Speaking of Google, I did also consider using a web browser in a kiosk mode (i.e full screen) and simply point it at the excellent Google Docs web application. Voilà! Break out the brews! Unfortunately, a quick proof-of-concept with the oldest Raspberry Pi model 1B+ demonstrated that it did not quite have the power to run Google Docs. Besides, that solution would have suffered from the same overall integration nightmare as the earlier idea with text editors, compounded by the dependency on almost-always-on network connection to the Google mothership not to mention having way more features than was actually desirable.
Rejecting the use of Google Docs did yield one valuable insight: I could very easily build the whole thing as a simple web application running in a web browser. This offers a rich and flexible development environment and a user experience that I can control completely. The only catch was that normally web applications cannot access any system resources outside of the browser’s security sandbox.
That limitation was easily solved by adding a lightweight local web server to provide controlled access to those privileged system resources. That includes managing user accounts and authentication, handling USB storage devices and document files as well as configuring network connections. This might seem like overly complicated solution to a relatively simple problem. Keep in mind though that the web server I am describing here does not need to serve millions of concurrent customers like my past commercial projects. It is simply a convenient and portable way to expose a set of APIs to a web application. Besides, I did have several ulterior motives:
- Keeping both the browser-based application code as well as the server code highly portable allowed me to prototype, develop, test and run the code fully on much more powerful desktop PCs and Macs before deploying it onto the Pi.
- Even after deploying the code onto the Pi, I could continue to test the whole stack simply by pointing my desktop browser at the Pi’s address. I could even load the web application locally on my PC and point it at the server running on the Pi, which came in handy for rapid iteration.
- With minimal coding effort, it enabled the full rich user experience that is possible using modern day HTML/JS/CSS: layout, scalable fonts, colors, images, icons, and so on.
- It helped enforce two very beneficial computer science practices, namely a clear separation of concerns and principle of least privilege between components.
- I could easily take the same exact software stack and drop it onto a hosted cloud server like Amazon Web Services (AWS) to turn this into a poor man’s version of Google Docs. That was obviously well outside of the original requirements, but it seemed like a nice bonus nevertheless.
Sum of Its Parts
Here’s an overview block diagram of the whole product.
The major software components I used are all open source or free software projects:
- Raspbian Jessie OS: a bare-bones Linux distribution specifically for the Raspberry Pi boards. I started from the current Jessie Lite version and added more software as needed, rather than starting from the full version and having to strip out or turn off unnecessary features.
- Matchbox: a minimal X Windows window manager for embedded applications.
- Midori: a minimal web browser that offers a full-screen kiosk mode. I considered KWeb as well but ultimately settled on Midori. Either one would have worked fine.
In addition to those existing components, I wrote two new components leveraging some more open-source projects:
- A web server built using the lightweight Sinatra framework written in Ruby. It launches at startup and can be accessed at http://localhost:8080. Besides providing the REST API to the web application, it serves up the HTML/JS/CSS files that make up the web application. The latter feature is strictly speaking not necessary for local operation, but enables remote access from other devices.
- A single-page web application built using AngularJS, Bootstrap, and Font Awesome. AngularJS makes it very easy to develop highly dynamic web applications, while Bootstrap and Font Awesome are there solely to make it look far prettier than my meager user interface design skills would otherwise allow.
The parts needed to build the device add up to about $150 excluding taxes & shipping. However, I actually spent about $75 as the only new supplies I had to purchase were the 7” touch screen ($60) and the stand/case ($25) as I salvaged the rest from my junk pile of assorted computer parts.
I started with an older Raspberry Pi model 1B+ board my wife had received as a freebie gift for interviewing at a tech company. Yay, the perks of living and working in Silicon Valley! That worked out well enough, though as the project progressed I decided to upgrade to a spare Raspberry Pi model 2B board for better performance.
You thought I was only joking about that junk pile? Tsk tsk.
At any rate, the ideal board for this project would be the current generation Raspberry Pi model 3 with its built-in WiFi and Bluetooth that saves on overall cost and leaves more USB ports free.
I chose a particular display case with LEGO compatible studs because my son happens to be a long-time LEGO builder. It offers him an outlet for additional creative pursuits not to mention a convenient parking spot for his LEGO-shaped USB flash drive. There is also a version of that display case with a smooth front if you prefer that cleaner look.
The keyboard is mostly a matter of taste. Since this is intended solely for text editing, there’s not much sense in buying a fancy keyboard, with or without number keypads, multimedia buttons or gaming controls, unless you prefer the ergonomics. A retro IBM PC clackety-clack keyboard could have been cool except for its obvious dangers to college dorm serenity. In the end, we chose a compact knock-off of the Apple aluminum keyboard with built-in backlight for those last-minute all-nighters to finish an essay that’s due tomorrow.
- $35 Raspberry Pi single-board computer (any model; the newer the better)
- $60 Raspberry Pi 7” touch screen
- $25 SmartiPi Touch case for RPi and display (LEGO version)
- $6 Raspberry Pi Power Supply
- $5 MicroSD card (8GB or more)
- $10 USB keyboard
- $5 USB mouse (optional, since the display is a touchscreen)
- $9 USB WiFi adapter (optional, and only if using Raspberry Pi model 2 or older)
- $155 total cost (excluding shipping and taxes)
Future Enhancement Ideas
There are a lot of things that could be done to further enhance this product. Here are some of the ideas I may pursue in the future:
Integrate with Cloud Storage Services
I opted not to implement the ability to store documents directly into Google Drive, Dropbox, etc. just yet, even though it would have been trivial. That was mostly just a prioritization call over other more important features and because I was not sure there would be reliable network access to make it worthwhile.
The user account passwords are secured using industry standard PKCS5 PBKDF2 and the authentication tokens are signed with a 2048-bit RSA key, yet the current system does have two vulnerabilities that bother me a bit:
- The local filesystem in the device itself is not encrypted. An evil maid could simply pop out the MicroSD card and pull all of the documents from it as cleartext.
- The local web server only provides an insecure HTTP connection, not HTTPS. That is OK for localhost access within the device. Accessing the device from a remote browser would expose sensitive information to eavesdropping and man-in-the-middle attacks. Because of this, the default production configuration of the web server denies remote access.
I did not yet enable upgrading the system software from digitally signed installation packages. This could be done either via USB flash drives or over the network from a server hosted on AWS.
In the meantime, I guess that just means my son has to come home for Thanksgiving. Oops.
Work Time Journal
This is also simple enough to implement, but I could not decide how to characterize work: should it count only time spent actively typing, or perhaps timeout after some idle time?
I wanted to keep the initial solution simple so there is currently only one version of any given document. Well, two, if you count the autosave version. Of course you can also manually save multiple versions of any document under different names.
Nevertheless, it might be useful to support versioning of documents. One simple way to accomplish that would be to leverage an existing version control tool such as git under the hood to manage the document revision history: every save then becomes a commit, and opening a document might offer the choice of revisions and diffs between them. This does not mean the user would need to know anything about git.
My son listens to music constantly as it helps him focus by shutting out other distractions. The Raspberry Pi is perfectly capable of playing music through its 3.5mm headphone jack. Implementing basic music playback was trivial. I simply ran out of time in designing a tolerable user experience for it, given that it would have introduced a new kind of background task.
The Raspberry Pi platform is amazingly capable for a $35 device: it can even play HD video. I thought of enabling video playback just because I can, but that would have introduced a true distraction rather just background noise like music playback.