Qt Quick with PyQt5 on Raspberry Pi

QtLogoThe prime motivation for me to go through Qt licensing documentation and installing Qt Creator IDE was to explore the new UI infrastructure introduced in Qt 5 under the umbrella of “Qt Quick“. As far as I can tell, this is an entirely different system for creating user interface of a Qt application. Built with modern ideas such as OpenGL graphics acceleration for animation effects and UI layout declared with a text-based markup language QML (probably stands for Qt Markup Language.)

Up to this point my experience with building graphics user interface in Qt was with the QWidget-based infrastructure, which has a long lineage in past editions of Qt. Qt Quick is new for Qt5 and seem to share nothing in common with QWidget other than both a part of Qt5. Now that I’ve had a bit of QWidget UI work under my belt I wanted to see what Qt Quick has to offer. And this starts with a smoke test to make sure I could run Qt Quick in the environments I care about: Python and Raspberry Pi.

Step 1: Qt Creator IDE Default Boilerplate.

Once the Qt Creator IDE was up and running, I followed the Qt Quick tutorial to create a bare bones boilerplate Qt Quick application. Even without any changes to the startup boilerplate, it reported error messages complaining of missing modules. Reading the error message, I looked at the output of apt list qml-module-qtquick* and installed the ones that sound right. (From memory:qml-module-qtquick2qml-module-qtquick-controls2, qml-module-qtquick-templates2, and qml-module-qtquick-layouts)

QML CPP

Once the boilerplate successfully launched, I switched languages…

Step 2: PyQt5

The next goal is to get it up and running on Python via PyQt5. The PyQt5 documentation claimed support for QML but the example on the introductory page doesn’t quite line up with the Qt Creator boilerplate code. Looking at the Qt Creator boilerplate main.cpp for reference, I translated the application launch code into main.py. This required sudo apt install python3-pyqt5.qtquick in addition to the python3-pyqt5 I already had. (If there are additional dependencies I forgot about, look for them in the output of apt list python3-pyqt5*)

QML PyQt

Once that was done, the application launched successfully on my Ubuntu desktop machine, albeit with visual appearance very different from the C++ version. That’s good enough for now, so I pushed these changes up to Github and switched platforms…

Step 3: Raspberry Pi (Ubuntu mate)

I pulled the project git repository to my Raspberry Pi running Ubuntu Mate and tried to run the project. After installing the required packages, I got stuck. My QML’s import QtQuick 2.7 failed with error module "QtQuick" version 2.7 is not installed The obvious implication is that the version of QtQuick in qml-module-qtquick2 was too old, but I couldn’t figure out how to verify version number is indeed the problem or if it’s a configuration issue elsewhere in the system.

Searching on the web, I found somebody on stackoverflow.com stuck in the same place. As of this writing, no solution had been posted. I wish I was good enough to figure out what’s going on and contribute intelligently to the discussion!

I don’t have a full grasp of what goes on in the world of repositories ran by various Debian-based distributions, but I could see URLs flying by on-screen and I remembered that Ubuntu Mate pulled from different repositories than Raspbian. I switched to Raspbian to give that a shot…

Step 4: Raspberry Pi (Raspbian Stretch)

After repeating the process on the latest Raspbian, the Qt Quick QML test application launches. Hooray! Whether it was some configuration issue or out of date binaries we don’t know yet for sure, but it does run.

That’s the good news. Now the bad news: it launches with the error:

JIT is disabled for QML. Property bindings and animations will be very slow. Visit https://wiki.qt.io/V4 to learn about possible solutions for your platform.

And indeed, the transition between “First” and “Second” tabs were slow. Looking on the page that it pointed to, it looks like the V4 JavaScript engine used by Qt for QML applications does not have JIT compilation for Raspberry Pi’s ARM chip. That’s a shame.

For now, this excludes Qt Quick as a candidate for writing modern responsive user interfaces for Raspberry Pi applications. If I want to stick with Qt and Python, I’m better off writing Qt interfaces in the old school QWidget style. We’ll keep an eye on this – maybe they’ll add JIT support for Raspberry Pi in the future.


(The source code related to this blog post are publicly available on Github.)

Qt Licensing Means Reading Big Walls of Text

QtLogoFrom a legal perspective, Qt is an interesting beast. There are two sets of licenses for application developers who wish to use Qt: a commercial license, or an open-source license. I’m sure this “dual-license” approach is intended to let people have the best of both worlds. In practice, it means people who try to do their legal due diligence will have to wade through a lot of legal language. It’s a very challenging barrier – most of the Qt Frequently Asked Questions page is devoted to licensing.

And that’s the condensed version. The legal Terms and Conditions section has multiple pages dedicated to different aspects of using Qt. As a non-lawyer, it’s very hard to not let my eyes gloss over the thick language. Even if we just focus on just the open-source side of the licensing, there is an array of licenses to worry about. There are the strong GPL , the more permissive BSD licenses, and the LGPL that attempts to strike a balance between them. I didn’t even know about LGPL until today. All of them are in play for various parts of Qt.

Fortunately, since my work so far is not for profit, and I intend to put everything up in public on Github, most of the terms of the open-source license should be easy to meet. I would definitely need to consult a lawyer before embarking on a commercial project, though.

With this basic due diligence complete, I went looking for the open-source edition of the Qt tools. They don’t exactly make it easy to find on the official Qt downloads page. It takes some persistence to navigate through the menu structures, looking for the de-emphasized texts and links, to find the download areas for the free open-source edition.

Before I found that compiled binaries repository, I found the information to build Qt5 and Qt Creator from source code. It seemed to be confused by the Qt (both 4 and 5) that appeared to already exist on my Ubuntu installation and I never got the home-built Qt5 up and running. After I stumbled across the binaries repository, I decided to come back to building Qt5 from source after I’ve gained a bit more experience with Linux build systems.

First Use of Python Threads is Quickly Followed By First Crash… in Qt

QtLogoBased on experience, I fully expected my first venture into Python multi-threading to run into problems. I just didn’t know exactly what that problem would look like. I had hoped that my first Python threading bug would be friendlier to understand and debug, just as the Python programming language has been friendlier for a beginner to write.

Sadly, no such luck. After I started using my GPIO class, with the debounce routine powered by threading.Timer, the crash is a very unfriendly Segmentation Fault. Surprisingly, it’s not the full “Segmentation Fault (core dumped)” so there was no core for me to debug with. No matter, it’s my program and I can relaunch it under gdb and try to dissect each instance of the crash.

The symptoms are consistent with a multi-thread timing issue:

  • It is unpredictable. I could use my program for several minutes without a problem, or the program might die within a few seconds of launch.
  • When something does go wrong, the actual point of failure that crashed in gdb is deep in the bowels of the system far from the actual problem.
    • In one case, a Python thread worker without any of my code on the stack.
    • In another case, internal system corruption error “Error in `python3': corrupted size vs. prev_size
  • The state of the rest of the system is also unpredictable. Using gdb’s “info threads” command I could get an overlook of the rest of the program, and it looks different every time.

I thought my timer-related code was simple: it checks the state of the input pin, and if the pin level has changed (after the debounce wait) also change the appearance of the visual indicator. The visual indication change was done by changing the stylesheet on the QWidget on screen. One of the error messages gave me my first clue that was my bug.

Could not parse stylesheet of object 0x21f6f58

Going back to look at the state of the other threads with this in mind, I saw they all had something in common: the main UI thread at the point of the crash is working on some part of visual rendering.

So we have a candidate explanation: I had been updating the QWidget stylesheet in the timer callback, which executes on a thread that is not the main Qt UI thread. So when this occurs when the UI thread is in the middle or rendering the QWidget, it would see the data structure change out from under it by the timer thread. This is not good and could explain the crash.

To test the hypothesis, I modified my program to perform stylesheet updates from the timer callback thread and do it frequently. Tens of times per second versus once every few seconds in my normal execution. The program now crashes consistently within a few seconds of launch which I saw as good confidence builder for my hypothesis.

The next thing we need is a fix. I need to make sure the stylesheet update occurs on the UI thread, and it seems simplest to post a message to the UI thread event queue. I can accomplish this by emitting a signal from the timer thread and have that go to a slot on the UI thread via a Queued Connection. The slot executes on the UI thread and can safely update the stylesheet there.

After this modification, the test program is now only emitting a signal from the timer callback thread to queue a stylesheet update, instead of performing the actual update itself on the timer thread. And now the test program no longer crashes.

I started debugging this believing I ran into a problem deep in the bowels of Python implementation internals. It turns out my clumsy use of threads had confused Qt.

Lesson learned, moving on to the next lesson…

(The project discussed in this blog post is publicly available on GitHub. The threading fix is in this commit.)

 

Learning Timers: Qt QTimer and Python threading.Timer

QtLogoWhen I interfaced my PyQt application to the Raspberry Pi GPIO pins, I ran into a classic problem: the need to perform input debouncing. The classic solution is to have the software wait a bit before deciding whether the input change is noise to be ignored or not. A simple concept, but “wait a bit” can get complicated in the world of GUI programming. When writing simple programs, we can probably get away with a literal wait by “going to sleep” for a little bit. But we don’t have that luxury in the world of GUI programming – going to sleep would freeze everything in the program. In general, users do not appreciate their UI becoming frozen and unresponsive.

Python LogoThe solution: a timer. In a Windows application, the programmer can use the operating system timer and do their “after waiting a bit” tasks in response to the WM_TIMER message. I went looking for the Qt equivalent and found several timer-related features. QTimer, QBasicTimer, and QObject::startTimer(). Thankfully, the documentation also provided an overview describing how they differ. For debounce purposes, the most fitting mechanism is a single-shot timer.

Unfortunately, when I tried to use it, I received an error message telling me I could only use Qt timer objects from code launched with QThread. Which apparently wasn’t the case with code running under the context of a QWidget within a QApplication.

I had hoped the Qt timers, working off of the QApplication event queue, would stay on the UI thread. But it appears they have to have their own QThread. I could put in more time to figure out how to get Qt timers to work, but I decided to turn to Python library instead. If I have to deal with multi-threading issues anyway, there’s no reason to avoid Python’s Timer object in the threading library.

It does mean I had to review my code to make sure it would be correct even if called from multiple threads. Since the important state are the status of the GPIO pins, they are handled by the pigpio library and the code in my app should be fairly safe. I do set a flag to avoid creating multiple Timer objects in the case of input bounce. If I cared about making sure I only ever create a single Timer, this flag should be protected against cross-thread access. But reviewing the code I decided it was OK if a few Timer ends up being created – the final result of reading the GPIO pin should still be the same even in the case of multiple Timers doing duplicate work.

(The project discussed in this blog post is publicly available on Github.)

Notes on “ZetCode’s PyQt5 Tutorial” From a Windows Developer.

QtLogoOnce I decided to learn how to create a GUI application using the PyQt5 Python binding for the Qt framework, I looked online for some resources to get started. The reference guides for PyQt5 and Qt version 5 itself seems to be fairly robust, but I needed a little push to get over the initial learning curve to understand where to look for what I need.

The Python Foundation’s wiki for PyQt tutorials has a fairly long list. But when I looked, only one explicitly states it is for PyQt5. So off I go to Zetcode’s PyQt5 Tutorial. It was a very bare-bones tutorial that might be a bit too bare for a complete beginner trying to learn GUI programming. But for somebody who already knows the general concepts of a windowing graphics interface system, it is a quick primer to learn the vocabulary.Python Logo

Since I’ve worked with various flavors of Windows frameworks (from raw Win32, to MFC, to WPF) I just needed a tutorial to help me connect concepts in my head to the terminology used in Qt. For example: in Qt, when something happens, a notification called a “signal” occurs. A signal can be connected to a “slot” which can then respond to whatever just happened. Once I learned this, I was able to translate the concepts into my head: a “signal” is an event that could be raised, and a “slot” is an event handler. Once I got this and a few other basic “Rosetta Stone” translations in my head I could switch to the reference documentation to find answers.

One important note: Even though it is labelled as a PyQt5 tutorial, Zetcode’s tutorial is actually pretty much the PyQt4 tutorial updated with the changes to syntax needed for PyQt5. It doesn’t actually cover anything that is new in Qt5. For me this is fine, because the “old way” covered in the tutorial is probably what I’ll end up using when I go even further back in time for the ROS flavor of Qt.

But know there’s no coverage of the Qt5 advancements in declarative interface construction, hardware-accelerated rendering, etc. Anybody who wants to learn the new toys of Qt 5 would have to look elsewhere.

Qt + Python = GUI for Raspberry Pi Project

Since the mission of the Raspberry Pi foundation is to “put the power of digital making into the hands of people all over the world” there is no shortage of options for programming the Pi. We have at our disposal many choices in programming languages, each with multiple application frameworks, and a large community of Raspberry Pi users for support.

QtLogoFeeling overwhelmed with options, I chose the one that best lines up with my long-term goal of getting up and running on ROS. The ROS plug-in architecture for operator GUI is rqt, based on Qt. And like much of ROS, the user has the option of working with rqt in either C++ or Python. Since I had started dabbling with ROS in Python before getting distracted, I thought the combination of Qt and Python would be a good direction to go.Python Logo

The Qt framework itself is aimed at C++ developers, and its documentation is written accordingly. Fortunately there are translation layers (language bindings) for Python. The one that seems to be the most mature is PyQt with a long list of resources, books, and online tutorials.

The next decision to make is which version to start learning. Browsing through the resources, it looks like Qt 4 is the mainstream version and Qt 5 is the new shiny. Since ROS is still in the midst of transitioning from Python 2 to Python 3, I assume rqt would be relatively old school as well. No matter which one I choose, there’ll be differences I have to tackle whenever I get around to diving deep into ROS. On the assumption that the latest and greatest versions are also the most polished (an assumption based on how Python 3 cleaned up a lot of architectural messiness of Python 2) I thought I’d start learning with the latest releases and make adjustments later as I need to.

So: Qt 5 and Python 3 it is, with the help of PyQt5 binding. Which is easily installed on a Raspbian Stretch system by installing the packages “pyqt5-dev” and “pyqt5-dev-tools”.

Less Grumpy About Python 3’s Break From Python 2.

Python LogoI spent more than a decade and a half in a software engineering job where backwards compatibility is a must, all day, every day. It’s very disorienting for me to switch to a world where such a sacred commandment would be discarded as when Python 3 was launched with severe incompatibilities from Python 2.

As a novice to Python, I was not aware of the problems that Python developers tried to leave behind in the break and I’m also ignorant of the positives Python 3 offered as a benefit to balance the cost. All I saw was the aftermath of an incredibly disruptive change that, almost a decade after it started, is still far from complete.

Part of my motivation to learn Python is ROS, which is still on Python 2. This meant I’ll have to deal with the transition costs even though I’m new to the scene. This was not a happy introduction to the world.

Fortunately the lengthy transition also meant there’s been time for people to voice similar concerns and for the people behind Python to write up their explanation. There’s a fairly lengthy explanation on Python.org titled “Should I use Python 2 or Python 3 for my development activity?” which links to an even lengthier “Python 3 Q&A” that has evolved over the past five years.

After reading it all, I see their point. Especially the parts around Unicode support. I can see how changing behavior of a fundamental concept like strings in a language can’t be done without breaking compatibility, and I can understand why it is a required transition for the language to be successful in the rest of the world beyond the English-speaking communities.

I don’t have to be happy about it, but I can at least understand it, and that does help to make me a little less grumpy when I have to deal with the aftermath.

Scratching the Surface of Python Libraries

Python Logo
Python logo from the Python Foundation

It’s somewhat embarrassing to admit my first impressions of Python came from programmer humor. The first one I can recall is xkcd #353. Another one that made an impression was the “If programming languages were essays” series.

The common thread is the tremendous library of tools available to python programmers just a “import” command away. I think the hard part of me getting up to speed in Python won’t be the syntax or the constructs, it’ll be getting to know what libraries are available. I foresee my biggest hurdle to Python productivity would be spending three hours writing something before it occurs to me to look for a library where someone has already done the work, find it, and finish the task in 15 seconds.

It makes sense that this ecosystem of libraries is a huge strength to Python and also an equally huge liability and a hindrance in transition to Python 3. By breaking backwards compatibility, Python 3 had to rebuild this ecosystem of libraries from scratch. It’s hard for people to find motivation to use the new Python 3 – with its limited set of ported libraries – when they could stay with the comfortable group of friends they already know in the Python 2 world.

To learn the ropes, there’s nothing like diving right in. I wanted to write a simple script to handle a task I had: enumerate video files in my collection and call FFmpeg to convert them from their old formats to the modern MPEG 4 Video format (h264 + AAC). Most of what I need to do for walking the directory tree comes from “import os” and “import os.path“. Calling FFmpeg turns out to be trivial after “import subprocess“. And the final icing on the cake: a library to parse command-line parameters using “import argparse“. Argparse even has a HOWTO tutorial to walk me through using it.

In less than an hour, this complete novice was able to build a decently robust Python script for video conversion.  Color me impressed.

tumblr_lltzgnhi5f1qzib3wo1_400

Some Python Points of Interest to a C/C++/C# Programmer

Python Logo
Python logo from the Python Foundation

Zipping through the Python 3 tutorial from the Python Foundation, some things stood out more than others. Coming from a background of work in C, C++, and C#, I found the following items interesting:

Strings

String handling is something every programming language has to deal with and a good way to feel how the language designers solve problems. C approaches bare metal and has historically proven to be error prone. C++ offers the choice of going with C or taking the performance overhead of string libraries in exchange for reduced headaches. C# reflects a more recent school of thinking where the programmer is prevented from shooting themselves and all their customers in their collective feet. Python is in the last bucket and I’m happy to see it.

A different ‘for’ loop

Python’s for loops always iterate over items of a sequence, and not based on an integer index like I’m used to from C and C++. It feels like foreach from C# but hopefully without the negative performance impact.

An ‘else’ block after a loop?

The ‘else’ block of a loop was a novel idea to me. I’ve never had this tool in my toolbox and my brain isn’t used to structuring code to take advantage of this mechanism, but I am optimistic I will find it useful.

Python classes

The Python designers took a very different path to implement classes than any other object-oriented language I’ve learned. The tutorial began with some background, a big wall of text that I originally thought I’d skip thinking it’d be repeating things I already knew. Now I’m glad I put in the effort to read it. Python classes look familiar at first glance, but after reading about the nuts and bolts, I know I’ll get into trouble if I had treated them the same way as C++ classes.

I expect I’ll still get into trouble, but now I’m optimistic I will understand why and be able to dig my way out.

Learning Python 3 (not 2) from Tutorial by Python Foundation

Python Logo
Python logo from the Python Foundation

I took the Codecademy Python class several months ago when I surveyed various technologies. It appears I didn’t write a short note about it which is too bad because I now want to look over what I thought at the time. In my vague memory, they wrote it for the absolute beginner and spend a lot of time teaching basic computer programming concepts. (Variables, flow control, etc.)

Python is again as a topic of interest for me. It is one of the primary languages for working with ROS and also in a lot of machine learning/AI fields. (OpenAI gym is Python, Google’s TensorFlow is primarily focused Python, etc.) I think I should try to gain proficiency in the language but I didn’t want to go through a beginner-focused class again.

To review Python from a different starting point, I started going through the Python Foundation’s own tutorial for Python 3.6. I quickly determined the target audience are people already familiar with programming in another language and want to get up to speed in Python, which perfect for me! It was quite useful for me when the authors described Python features in terms of how it is similar to or different from C++ features.

On the flip side, I was reminded why I was down on Python: the incompatible break between Python 2 and Python 3. They’re both fundamentally the same language but in real world usage they are now effectively two different languages. Python libraries written for Python 2 could not run unmodified on Python 3, and vice versa. So they will have different install instructions, etc. Over eight years after the initial release of Python 3 the entire ecosystem is still undergoing the pain of  this transition.

OpenAI and TensorFlow appears to support both Python 2 and 3, with separate setup and usage instructions. ROS has the official  ambition to move to Python 3 but is currently still stuck on Python 2 due to the existing base of Python libraries.

Despite the temptation to stick with Python 2 for ROS, I decided to jump into the Python 3 tutorial and I’ll deal with Python 2 weirdness as they come up later.

See World(s) Online

NASALogoOne of the longest tenure items on my “To-Do” exploration is to get the hang of the Google Earth API and learn how to create a web app around it. This was very exciting web technology when Google seemed to be moving Google Earth from a standalone application to a web-based solution. Unfortunately its web architecture was based around browser plug-ins which eventually lead to its death.

It made sense for Google Earth functionality to be folded into Google Maps, but that seemed to be a slow process of assimilation. It never occurred to me that there are other alternatives out there until I stumbled across a talk about NASA’s World Wind project. (A hands-on activity, too, with a sample project to play with.) The “Web World Wind” component of the project is a WebGL library for geo-spatial applications, which makes me excited about its potential for fun projects.

The Java edition of World Wind has (or at least used to) have functionality beyond our planet Earth. There were ways to have it display data sets from our moon or from Mars. Sadly the web edition has yet to pick up that functionality.

JPL does currently expose a lot of Mars information in a web-browser accessible form on the Mars Trek site. According to the speaker of my talk, it was not built on World Wind. He believes it was built on Cesium, another WebGL library for global data visualization.

I thought there was only Google Earth, and now I know there are at least two other alternatives. Happiness.

The speaker of the talk is currently working in the JPL Ops Lab on the OnSight project, helping planetary scientists collaborate on Mars research using Microsoft’s Hololens for virtual presence on Mars. That sounds like an awesome job.

Fusion 360 vs. Onshape: Raspberry Pi

raspberry-pi-logoAnd now for something completely silly: let’s look at how our two competing hobbyist-friendly CAD offerings fare on the hobbyist-friendly single-board computer, the Raspberry Pi.

(Spoiler: both failed.)

Raspberry Pi

I have on hand the Raspberry Pi 3 Model B. Featuring a far more powerful CPU than the original Pi which finally made the platform usable for basic computing tasks.

When the Raspberry Pi foundation updated its Raspbian operating system with PIXEL, they switched the default web browser from Epiphany to Chromium, the open-source fork of Google’s Chrome browser. Bringing in a mainstream HTML engine resulted in far superior compatibility with a wider range of web sites, supporting many of the latest web standards, including WebGL which is what we’ll be playing with today.

Autodesk Fusion 360

Fusion 360 is a native desktop application compiled for Windows and MacOS, so we obviously couldn’t run that on the Pi. However, there is a web component: Fusion 360 projects can be shared on the Autodesk 360 collaboration service. From there, the CAD model can be viewed in a web browser via WebGL on non-Windows/MacOS platforms.

While such files can be viewed on a desktop machine running Ubuntu and Chromium, a Raspberry Pi 3 running Chromium is not up to the task. Only about half of the menu bar and navigation controls are rendered correctly, and in the area of the screen where the actual model data should be, we get only a few nonsensical rectangles.

Onshape

Before this experiment I had occasionally worked on my Onshape projects on my desktop running Ubuntu and Chromium, so I had thought the web-based Onshape would have an advantage in Raspberry Pi Chromium. It did, just not usefully so.

In contrast to A360’s partial menu UI rendering, all of Onshape’s menu UI elements rendered correctly. Unfortunately, the actual CAD model is absent in the Raspberry Pi Chromium environment as well. We get the “Loading…” circle and it was never replaced by the CAD model.

Conclusion

Sorry, everyone, you can’t build a web-based CAD workstation with a $35 Raspberry Pi 3.

You can, however, use these WebGL sites as a stress test of the Raspberry Pi. I had three different ways of powering my Pi and this experiment proved enlightening.

  1. A Belkin-branded 12V to 5V USB power adapter: This one delivered good steady voltage at light load, but when the workload spiked to 100% the voltage dropped low enough for the Pi to brown out and reset.
  2. A cheap Harbor Freight 12V to 5V USB adapter: This one never delivered good voltage. Even at light load, the Pi would occasionally flash the low-voltage warning icon, but never low enough to trigger a reboot. When the workload spiked to 100%, the voltage is still poor but also never dropped enough to trigger a reset. Hurray for consistent mediocrity!
  3. An wall outlet AC to 5V DC power unit (specifically advertised to support the Raspberry Pi) worked as advertised – no low-voltage warnings and no resets.

Static Web Site Hosting with Amazon S3 and Route 53

aws_logoWeb application frameworks have the current spotlight, which is why I started learning Ruby on Rails to get an idea what the fuss was about. But a big framework isn’t always the right tool for the job. Sometimes it’s just a set of static files to be served upon request. No server-side smarts necessary.

This was where I found myself when I wanted to put up a little web site to document my #rxbb8 project. I just wanted to document the design & build process, and I already had registered the domain rxbb8.com. The HTML content was simple enough to create directly in a text editor and styled with CSS from the Materialize library.

After I got a basic 1.0 version of my hand-crafted site, I uploaded the HTML (and associated images) to an Amazon S3 bucket. It only takes a few clicks to allow files in a S3 bucket to be web-accessible via a long cumbersome URL on Amazon AWS domain http://rxbb8.com.s3-website-us-west-2.amazonaws.com. Since I wanted this content to be accessible via the rxbb8.com domain I already registered, I started reading up on the AWS service named in geek-humor style as Route 53.

Route 53 is designed to handle the challenges of huge web properties, distributing workload across many computers in many regions. (No single computer could handled all global traffic for, say, netflix.com.) The challenge for a novice like myself is to figure out how to pull out just the one tool I need from this huge complex Swiss army knife.

Fortunately this usage case is popular enough for Amazon to have written a dedicated developer guide for it. Unfortunately, the page doesn’t have all the details. The writer helpfully points the reader to other reference articles, but those pages revert back to talking about complex deployments and again it takes effort to distill the simple basics out of the big feature list.

If you get distracted or lost, stay focused on this Cliff Notes version:

  1. Go into Route 53 dashboard, create a Hosted Zone for the domain.
  2. In that Hosted Zone, AWS has created two record sets by default. One of them is the NS type, write down the name servers listed.
  3. Go to your domain registrar and tell them to point name servers for the domain to the AWS name servers listed in step 2.
  4. Create S3 storage bucket for the site, enable static website hosting.
  5. Create a new Record Set in the Route 53 Hosted Zone. Select “Alias” to “Yes” and point alias target to the S3 storage bucket in step 4.

Repeat #4 and #5 for each sub-domain that needs to be hosted. (The AWS documentation created example.com and repeated 4-5 for www.example.com.)

And then… wait.

The update in step 3 needs time to propagate to name servers across the internet. My registrar said it may take up to 24 hours. In my case, I started getting intermittent results within 2 hours, but it took more than 12 hours before everything stabilized to the new settings.

But it was worth the effort to see version 1.0 of my created-from-scratch static web site up and running on my domain! And since it’s such a small and simple site with little traffic, it will cost me only a few pennies per month to host in this manner.

rxbb8.com.v1

Let the App… Materialize!

materializecsslogoAfter I got the Google sign-in working well enough for my Rails practice web app, the first order of business was to build the basic skeleton. This was a great practice exercise to take the pieces I learned in the Ruby on Rails Tutorial sample app and build something of my own design.

The initial pass implemented basic functionality but it didn’t look very appealing. I had focused on the Rails server-side code and left the client-side code simple plain HTML that would have been state-of-the-art in… maybe 1992?

Let’s make it look like something that belongs in 2017.

The Rails tutorial sample app used Bootstrap to improve the appearance and functionality of the client-side interface. I decided to take this opportunity to learn something new instead of doing the same thing. Since I’m using Google Sign-In in this app, I decided to adopt Google’s design concepts to my client-side appearance as well.

Web being the web, I knew I wouldn’t have to start from scratch. I knew about Google’s own Material Lite and thought that would be a good candidate before I learned it had been retired in favor of its successor, Material Components for the web. One of the touted advantages was improved integration with different web platforms. Sadly Rails was not among the platforms with examples ready-to-go.

I looked around for an existing project to help Rails projects adapt Google’s design language, and that’s when I found Materialize: A library that shares many usage patterns with Bootstrap. The style sheets are even written using SASS, native to default Rails apps, making for easy integration. Somebody has done that work and published it as Ruby gem materialize-sass, so all I had to do was add a single line to use Materialize in my app.

Of course I still had to put in the effort to revise all the view files in my web app to pick up Materialize styling and features. That took a few days, and the reward for this effort is a practice web app which no longer look so amateurish.

The Cost for Security

In the seemingly never-ending bad news of security breaches, a recurring theme is “they knew how to prevent this, but they didn’t.” Usually in the form of editorializing condemning people as penny-pinching misers caring more about their operating cost than the customer.

The accusations may or may not be true, it’s hard to tell without the other side of the story. What’s unarguably true is that security has some cost. Performing encryption obviously takes more work than not doing any! But how expensive is that cost? Reports range wildly anywhere from less than 5% to over 50%, and it likely depends on the specific situations involved as well.

I really had no idea of the cost until I stumbled across the topic in the course of my own Rails self-education project.

I had designed my Rails project with an eye towards security. The Google ID login token is validated against Google certificates, and the resulting ID is salted and hashed for storage. The code for this added security were deceptively minor, as they triggered huge amounts of work behind the scenes!

I started on this investigation because I noticed my Rails test suite ran quite slowly. Running the test suite for the Rails Tutorial sample app, the test framework ran through ~120 assertions per second. My own project test suite ran at a snail’s pace of ~12 assertions/second, 10% of the speed. What’s slowing things down so much? A few hours of experimentation and investigation pointed the finger at the encryption measures.

Obviously security is good for the production environment and should not be altered. However, for the purposes of development & test, I could weaken them because there would be no actual user data to protect. After I made a change to bypass some code and reducing complexity in others, my test suite speed rose to the expected >100 assertions/sec.

Granted, this is only an amateur at work and I’m probably making other mistakes doing security inefficiently. But as a lesson to experience “Security Has A Cost” firsthand it is eye-opening to find a 1000% performance penalty.

For a small practice exercise app like mine, where I only expect a handful of users, this is not a problem. But for a high-traffic site, having to pay ten times the cost would be the difference between making or breaking a business.

While I still don’t agree with the decisions that lead up to security breaches, at least now I have a better idea of the other side of the story.

Protecting User Identity

google-sign-inRecently, web site security breaches have been a frequent topic of mainstream news. The technology is evolving but this chapter of technology has quite some ways to go yet. Learning web frameworks gives me an opportunity to understand the mechanics from web site developer’s perspective.

For my project I decided to use Google Identity platform and let Google engineers take care of identification and authentication. By configuring the Google service to retrieve only basic information, my site never sees the vast majority of personally identifiable information. It never sees the password, name, e-mail address, etc.

All my site ever receives is a string, the Google ID. My site uses it to identify an user account. With the security adage of “what I don’t know, I can’t spill” I thought this was a pretty good setup: The only thing I know is the Google ID, I can’t spill anything else.

Which led to the next question: what’s the worst that can happen with the ID?

I had thought the ID is something Google generated for my web site. More specifically my site’s Client ID. I no longer believe so. A little experimentation (aided by a change in Client ID for the security issue previously documented) led me to now believe it’s possible the Google ID is global across all Google services.

This means if a hacker manages to get a copy of my site’s database of Google ID, they can cross-reference to databases of other compromised web sites. Potentially assembling a larger picture out of small pieces of info.

While I can’t stop using Google ID (I have to have something to identify an user) I can make it more difficult for a hacker to cross-reference my database. I’ve just committed a change to hash the ID before it is stored in the database. Salted with a value that is unique per deployed instance of the app.

Now for a hacker to penetrate the identity of my user, they must do all of the following:

  1. Obtain a copy of the database.
  2. Obtain the hashing salt used by the specific instance of the app which generated that database.
  3. Already have the user’s Google ID, since they won’t get the original ID out of my database of hashed values.

None of which are impossible, but certainly a lot more effort than it would have otherwise taken.

I think this is a worthwhile addition.

Adventures in Server-Side Authentication

google-sign-inThe latest chapter comes courtesy of the Google Identity Platform. For my next Rails app project, I decided to venture away from the user password authentication engine outlined in the Hartl Ruby on Rails Tutorial sample app. I had seen the “Sign in with Google” button on several web sites (like Codecademy) and decided to see it from the other side: Users for my next Rails project will sign in with Google!

The client-side code was straightforward following directions in the Google documentation. The HTML is literally copy-and-paste, the JavaScript needed some reworking to translate into CoffeeScript for the standard Rails asset pipeline but wasn’t terribly hard.

The server side was less straightforward.

I started with the guide Authenticate with a Backend Server which had links to the Google API Client Library for (almost all) of the server side technologies including Ruby. The guide page itself included examples on using the client library to validate the ID token in Java, Node.JS, PHP, and Python. The lack of Ruby example would prove problematic because each flavor of the client library seems to have different conventions and use different names for the functionality.

Java library has a dedicated GoogleIdTokenVerifier class for the purpose. Node.JS library has a GoogleAuth.OAuth2 class with a verifyIdToken method. PHP has a Google_Client class with a verifyIdToken method. And to round out the set, Python library has oauth2client.verify_id_token.

Different, but they’re all in a similar vein of “verify”, “id”, and “token” so I searched the Ruby Google API client library documentation for those keywords in the name. After a few fruitless hours I concluded what I wanted wasn’t there.

Where to next? I went to the library’s Github page for clues. I had to wade through a lot of material irrelevant to the immediate task because the large library covers the entire surface of Google services.

I thought I had hit the jackpot when I found reference to the Google Auth Library for Ruby. It’s intended to handle all authentication work for the big client library, with the target completion date of Q2 2015. (Hmm…) Surely it would be here!

It was not.

After too many wrong turns, I looked at Signet in detail. It has a OAuth2::Client class, which sounded very similar to the other libraries, but it had no “verify” method so every time I see a reference to Signet I keep deciding to look elsewhere. Once I decided to read into the details of Signet::OAuth2::Client, I finally figured out that it had a decoded_id_token method that can optionally verify the token.

So it had the verification feature but the keyword “verify” itself wasn’t in the name, throwing off my search multiple times.

Gah.

Nothing to do now but to take some deep breaths, clear out the pent-up frustration, and keep on working…

Simple Online Digital Photo Frame

The CarrierWave Playground project was created for experimentation with image upload. As intended, it helped me learn things about CarrierWave such as creating versions of the image scaled to different resolutions and extracting EXIF image metadata.

Obviously the image has to be displayed to prove that the upload was successful. I hadn’t intended to spend much time on the display side of things, but I started playing with the HTML and kept going. Logic was added for the browser to report its window size so the optimal image could be sent and scaled to fit. I had a button to reload the page, and it was fairly simple to change it from “reload the current page” to “navigate to another page”. Adding a JavaScript timer to execute this navigation… and voila! I had myself a rudimentary digital photo frame web app that loads and displays image in a sequence.

It’s fun but fairly crude. Brainstorming the possibilities, I imagine the following stages of sophistication:

Stage 1 – Basic: Where I am now, simple JavaScript that performs page navigation on a timer.

Problem: page blinks and abruptly shifts as new page is loaded. To avoid the abrupt shift, we have to eliminate the page switch.

Stage 2 – Add AJAX: Instead of a page navigation, perform a XMLHttpRequest to the server asking for information on the next image. Load the image in the background, and once complete, perform a smooth transition (fade out/fade in/etc.) from one image to the next.

Problem: Visual experience is at the mercy of the web browser, which probably has an address bar and other UI on screen. Also, the user’s screen will quickly go dark due to power saving features. To reliably solve both, I will need app-level access.

Stage 3 – Vendor-specific wrapper: Every OS platform has a way to allow web site authors an express lane into the app world. Microsoft offers the Windows App Studio. Apple has iOS web applications. Google has Android Web Apps.

Unknown: The JavaScript timer is a polling model, do we gain anything by moving to a server-push model? If so, that means…

Stage 4 – WebSocket: Photo updates are triggered by the server. Since I’m on Rails, the most obvious answer is to do this via WebSockets using Action Cable.

Looking at the list, I think I can tackle Stage 2 pretty soon if not immediately.

Stages 3 and 4 are more advanced and I’ll hold off for later.

EXIF fun with CarrierWave uploader

To play with the CarrierWave uploader gem I created a new Rails project just for the purpose of experimentation. I had thought about doing this as part of the Hartl Rails Tutorial sample app but ultimately decided to keep things as bare-bones as I can.

When trying to understand a new system, a debugger is a developer’s best friend. Part of this exercise is to get my feet wet using a debugger to poke around a running Rails app. The Hartl Rails Tutorial text introduced the byebug gem but only minimally covered usage. The official Rails Guides had more information which helped me get going, in addition to various users writing up their own cheat sheets.

I decided to dig into image metadata. Basic information such as width and height were made available as img[:width] and img[:height] but where are the others? With the help of byebug I found that they were available in the img.data hash. Most of the photography-specific EXIF metadata are in there as well, though somebody interested only in that subset can access it via the img.exif hash.

As an exercise I decided to try to pull out the original date. Time stamp on digital photography files have always been a headache. Most computer OS track “Created Date” and “Modified Date” but they are relative to the computer and not reliable for photo organization purposes. Photo editing introduces another twist: if an image is created from a photograph, the time stamp would be the day the edit operation was made and not when the original photo was taken.

Which is how I ended up looking at EXIF “DateTime”, “DateTimeOriginal”, and “DateTimeDigitized” to take the earliest date of the three (when present).  Then I ran into another can of worms: time zones. The EXIF time stamp have no time zone information, but the Ruby DateTime object type does. Now my time stamps are interpreted as UTC when it isn’t. Since EXIF doesn’t carry time zone data (that I can find) I decided to leave that problem to be tackled another day.

Behavior Driven Development

cucumberlogoMy new concept of the day: Behavior Driven Development. As this beginner understands the concept, the ideal is that the plain-English customer demands on the software is formalized just enough to make it a part of automated testing. In hindsight, a perfectly logical extension of Test-Driven Development concepts, which started as QA demands on software treated as the horse instead of the cart. I think BDD can be a pretty fantastic concept, but I haven’t seen enough to decide if I like the current state of the art in execution.

I stumbled into this entirely by accident. As a follow-up to the Rails Tutorial project, I took a closer look at one corner of the sample app. The image upload feature of the sample app used a gem called carrierwave uploader to do most of the work. In the context of the tutorial, CarrierWave was a magic black box that was pulled in and used without much explanation. I wanted to better understand the features (and limitations) of CarrierWave for use (or not) in my own projects.

As is typical of open-source projects, the documentation that exists is relatively thin and occasionally backed by the disclaimer “for more details, see source code.” I prefer better documentation up front but I thought: whatever, I’m a programmer, I can handle code spelunking. It should be a good exercise anyway.

Since I was exploring, I decided to poke my head into the first (alphabetically sorted) directory : /features/. And I was immediately puzzled by the files I read. The language is too formal to be conversational English for human beings, but too informal to be a programming language as I knew one. Some amount of Google-assisted research led me to the web site for Cucumber, the BDD tool used by the developers of CarrierWave.

That journey was fun, illuminating, and I haven’t even learned anything about CarrierWave itself yet!