Building Lyft’s Next Emblem — Glow
By: Avneet Oberoi, Michael Vernier, Phoenix Li, Masroor Ahmed
Introduction
Long time riders might remember the original fuzzy, pink Carstache emblem that made Lyft universally recognizable. Over the years, the emblem dropped the fuzz for pink lights in the Glowstache and later evolved with more colors as the beloved Amp, which has been in active use for over seven years! Recently, Lyft has introduced its brighter, bolder next generation emblem — Glow. Glow provides a daytime visible, auto-dimmable display showing rider customizable colors and new animations to help them find their ride faster. Glow also has enhanced GPS and IMU sensors for improved driver location accuracy.
Figure 1: In app rider experience for Glow ride
Prior to Glow, Lyft has IoT development experience with not only the Amp but also with Bikes and Scooters, Halo ad displays, and even Autonomous research vehicles. Each of these were built with bespoke solutions for their use case, which were hard to retrofit for new device types. Observing similar functionality across these siloed systems motivated us to collaborate with these teams, where feasible, to build new IoT middleware services which could provide a unified framework for managing a variety of devices.
High Level Overview
Figure 2: Simplified high level overview
Just like for the Amp, we continue to use Bluetooth Low Energy (BLE) as the communication mechanism between the Glow device and the driver’s smartphone, instead of opting for a cellular chip in the device. We leverage the driver’s phone as an “IoT gateway” which serves as a communication link between the Glow device and the Lyft backend.
The Lyft backend consists of services which act as the brain of the whole operation, determining everything from whether the driver is eligible to use a Glow, to controlling every aspect of the driver’s Glow.
The Glow device itself is controllable via a well defined request-response based command framework that was developed in-house based on our requirements.
This post will detail a few simplified foundational components that make up the IoT system for the Glow including:
- Provisioning and Authentication
- Control and Communication
- State Management including the firmware update process
Lastly, we’ll briefly discuss what’s next for the Glow program.
Provisioning and Authentication
For any IoT device, provisioning refers to the process of creating a unique identifier for each device and registering the device in a central Device Registry, so that the state of each one in the fleet can be tracked and managed.
Common provisioning processes typically involve:
- Flashing a bootstrap URL onto the device during manufacturing and then letting the device self-identify by connecting to the URL when activated.
- Having the end user manually register their device through an app or website when they start using the device.
After a device has been provisioned into the Device Registry, future communication with the device requires authentication to verify the device is genuine before it engages with the IoT system. Authentication mechanisms such as verification of on-device certificates, symmetric or asymmetric key cryptography, or more sophisticated hardware solutions can be employed depending on the sensitivity of the data being transferred to and from the device.
For the Amp, we simply relied on treating the MAC address of the Amp device as its unique identifier, which would be read by the driver’s phone and relayed to the backend. Phone manufacturers though can choose to anonymize MAC addresses, providing an obfuscated and random hash of the MAC address every time it is read. Additionally, we had no concept of a dedicated Device Registry then and were simply associating each device’s MAC address with a driver record. Since each device could report multiple identities, we faced obvious challenges with device state management and accurate user-to-device association and tracking.
In order to circumvent the problems faced with the Amp, we designed the following on-the-fly provisioning process for the Glow:
- Each Glow device is assigned a unique serial number during the manufacturing process. This number is stored within the Glow’s internal flash storage and on a barcode which is affixed to the device packaging.
- As part of shipping a device to a driver, the above barcode is scanned and mapped to a specific Lyft driver in the Device Registry service. Once this is complete, the Glow is shipped out to its new owner.
- When the driver receives their Glow device and tries connecting it to their phone, the Lyft Driver app will leverage a pre-shared key and the serial number of the Glow to authenticate the device before any communication can begin.
The diagram below summarizes the different states that a Glow device transitions through, as described above.
Figure 3: Glow device state transitions
The above flow not only helps provide detailed device metadata and accountability for devices issued to drivers, but is also meant as a security measure. Unlike the Amp, a Glow device is made to only illuminate when it has successfully authenticated with the Lyft backend services and when the driver is actively driving for Lyft. This prevents malicious parties from impersonating Lyft drivers with a Glow device obtained from someone or somewhere other than Lyft.
Device Control and Communication
Each IoT device needs to be controllable by means of pre-determined operating instructions. These can be as trivial as turning the device on or off, or more involved, like playing a certain animation file on the LED display, such as for the Glow. A device is made remotely controllable through its firmware i.e. the on-device software responsible for deciphering and executing instructions to make the device operate as required.
The instruction set aka the “command set” built for the Glow is simple, yet powerful. It supports instructions to individually control various functionalities such as animation file playback, adjusting device brightness, uploading file to device storage and even monitoring on-device sensors. These types of fine grained device commands are also made highly configurable which enables robust, predictable, and easily extensible behavior from the Glow device.
As an example, the instruction for file uploads to the device unlocks the ability to add more animation options for riders to choose from in the future. The alternative would have been to bundle the additional files as part of a new firmware update, which would be much slower to build and roll out. Additionally, firmware resourcing is often more limited, delaying launch of even simple functionality like the above.
Device Control Flow
The Lyft backend is responsible for controlling the device using the command set described above. We built a backend service, “Device Controller”, which listens for different types of relevant event triggers to determine appropriate instructions for the driver’s Glow device. For example, when the service receives a trigger indicating that the driver is in close proximity to the rider’s pickup location, it issues an instruction for the Glow to play the rider selected pickup animation.
The mobile client acts as the communication gateway, helping with essential flows such as command relay and BLE protocol translation as well as buffering for data transfers when needed.
Each server generated command is delivered to the mobile client by means of a server streaming component which exists in Lyft’s infrastructure. The client simply needs to subscribe for the commands once a Glow is successfully connected to it, in order to receive real-time data from the server.
The entire command set has been divided into two categories, based on how the command is to be handled by the client:
- Passthrough commands: These are simple commands which do not require any pre-processing or state management by the mobile client and can be forwarded directly to the Glow device via BLE. Examples include updating the device’s brightness or updating the animation being played on the device.
- Complex commands: These typically require the client to pre-process payload data, download files from the Lyft backend, buffer data, or maintain some sort of state. Transferring files to the Glow is an action that requires complex commands. A single command is sent from the backend to the client. The client is responsible for first downloading the new files to internal storage, splitting the file into smaller chunks, and sending each chunk to the Glow in a separate command.
Some of the more nuanced details about command ordering/prioritization, data encoding, retry mechanism and encryption mechanism between the client and Glow have been omitted in order to avoid complicating the overall flow we’re trying to depict here.
All commands include a unique identifier to enable tracking of the control flow at any given time. The Glow will send a response for every command message it receives. This response will include whether the action succeeded or failed, an error message describing the failure, or any data that might have been requested by the command. All responses are transmitted to the Lyft backend so that they can be used to diagnose or debug issues.
The end to end flow has been summarized in the image below.