Bike LED Vest Swift 3

Earth Day is is here. Tonight, organizers set up a night time a bike ride encouraging creative ways to make yourself seen.  My daughter wanted to wear my LED vest and assumed it was just a matter of lighting it up. Needless to say, the iOS app crashed. Considering I  never tested it out with iOS 10.3, it was high time to start troubleshooting.

Because of the fact I used the objective-C BLE libs, the crash precipitated the move 100% swift solutions. For the purpose of this exercise, I forked the current the swift version and patched it to use XCGLogger, compiled it for swift 3.0, and added a couple of delegates for my own app. The changes can be found  at the forked site.

Incidentally, the crash was attributed parsing JSON results from a YML query to yahoo. The service URL changed and I cleaned up the code so it would not crash in the future should it change again.

Bike LED Vest Revisited

With Swift 3,  watchOS3, and iOS 10 released, it was time to migrate the code  from Swift 2.1 to Swift 3.0 using Xcode 8.0.  I still have use for my Myo armband but wanted to explore using Apple’s CoreMotion and HealthKit SDKs. The conversion tool in Xcode did a great job and most of it was dealing with optional chaining that required my attention. Once completed, the existing application worked as before. Although the bluetooth code migrated ok, I was left with a handful of deprecations warnings in iOS 10.0 that will need clean up so I can keep current on iOS releases.  For now, I wanted to explore how to use the iWatch Series 1 to achieve the following goals:

  • Capture Heart Rate and include with geolocation data in the  iPhone app
  • Detect and send turn signals to LED Vest
  • Display Temperature and Battery Voltage with alarm set points
  • Learn more about the Swift language, the various SDKs

Watch interface

Hats off to UIX designers. This does not come easy to me. I ended up purchasing Graphics (was iDraw) from Autodesk as it was affordable and comes with a rich feature set.  A nice bonus is that this tool can generate can generate Core Graphics “copy as” code.  Alas, my first pass works and leveraged the context menus to save on screen real estate.


Context Menu

The context menu used canned icons. The start/stop implement the obvious functionality.  The Speak functionality allows me to either send one of three messages or speak into the watch and send the resulting text to display on my LED Vest. The user interaction side was rather easy to implement using the presentTextInputController method of the WKInterfaceController class.

func sendLEDMessage() {
    let phrases = ["Smile. Be Happy.", "One day at a time", "Technology Rocks!"]

    presentTextInputController(withSuggestions: phrases,
        allowedInputMode: .plain,
        completion: { (result) -> Void in
                                    if let choice = result {
        if self.isHostCommunicating() {
            if let statement = choice[0] as ?String {
                let requestValues = ["command" : statement]
                let session = WCSession.default()
                session.sendMessage(requestValues, replyHandler: {
                    reply in
                                                    self.cmdStatus = reply["status"] as ?String
                }, errorHandler: {
                    error in
                                                    print("error: \(error)")




Swift extensions are your friend.  One can extend classes without access to source and add additional behaviour.  For example, to quickly implement alarm functionality, WKIntefaceLabel was extended to allow a refresh a label.

extension WKInterfaceLabel {
    func refresh(using:Float?, prefix:String, alarmConfig:AlarmPointConfiguration, comStatus:Bool)->Void {
// code here

 @IBOutlet var boardVoltage: WKInterfaceLabel!
boardVoltage.refresh(using: getBoardVoltage(), prefix:"V:", alarmConfig: boardVoltageAlarmConfig, comStatus: isLEDVestConnected())


Healthkit is a pain to get going using just Apple’s docs.  Fortunately, there are lots of tutorials out there to help get things going.  I would have liked to have more detailed information so one can track heart rate variability (HRV).  These folks are working on some cool stuff mashing technologies using HRV. It seems we are left with BPM samples at around 5 second intervals. I get why, given that there could be other apps wanting access to this information and sub second resolution in a device that was meant to tell time at first would overwhelm watchOS. I suspect one day this should be available.

Core Motion vs. Myo

I found Myo integration to detect hand signals easier to implement. It was more intuitive. On the Myo, the “home” position would be cached so relative changes in movement could be computed. e.g.  right hand turn gesture using pitch and left hand turns using yaw and roll. It works quite well.

func centerPositions(_ yawPosition: Double, pitchPosition: Double, rollPosition: Double) {
    centerYawPos = yawPosition
    centerPitchPos = pitchPosition
    centerRollPos = rollPosition
func isLeftTurn(_ currentRollPosition: Double, currentPitchPosition: Double) -> Bool  {

    guard centerRollPos != 0.0 else {
        log.debug(" Roll not centered. Left turn check ignored")
        return false

    curPitchPos = currentPitchPosition
    curRollPos = currentRollPosition

    deltaRoll = computeDelta(currentRollPosition - centerRollPos)
    deltaPitch = computeDelta(currentPitchPosition - centerPitchPos)
    let retVal = isHandSignal(currentRollPosition, minTolerance: leftTurnAngleMin, 
        maxTolerance: leftTurnAngleMax, centeredPosition: centerRollPos) && 
        isHandSignal(currentPitchPosition, minTolerance: 0.2 * leftTurnAngleMin, maxTolerance: 0.9 * leftTurnAngleMin, centeredPosition: centerPitchPos)

    if (retVal == true) {
        log.debug("Left turn detected")
        // leftTurnState = .Idle
        // isWantingLeftTurn = false

    return retVal


I could not get this to function using that same approach with consistent results on the iWatch.  I ended up working with just gravity component for hand signals position. e.g. right turn detection is using the X component of the accelerometer and the Y component for the left hand turn. Initially, I used CMDeviceMotion‘s CMAttitude  component and used multiply(byInverseOf: x) method of CMAttitude to get relative changes in motion.  It worked for the right hand turn but was inconsistent for the left hand turn.

The gravity only component with a range threshold range works ok for now. I will investigate the CMAttitude further and will look at integrating (summing changes along X,Y, Z over small sample windows to detect hand signals.

Bike LEDVest

I’ve been tossing this project in my head for a few years. I signed up when the Myo Armband came out on kickstarter and figured I could make use of it one day.   When I purchased the the Apple Watch, then that got the wheels in motion to build an LEDVest.

Some of the goals I wanted to achieve included the following:

  • Learn the iOS development (Swift language)
  • Drill down on Bluetooth LE development
  • Persist information on iCloud and retrieve from different devices
  • Create something useful and provides context based information to others while riding my bicycle at night
  • Explore iOS HealthKit and MapKit

Screen Shot 2016-02-06 at 5.26.43 PM



My wife did all the sewing. The LED’s are so bright that the iPhone camera does not do it justice inside. Many people commented from motorists, pedestrians, and cycles on how cool this vest was.

It took a lot of effort but it was a nice diversion from the day job. Learning a new programming language, organizing the code so that the appropriate level of abstractions exist to easily add new features, creating an application level protocol to control the LEDVest, and designing and building simple hardware bumped up the fun factor.

Using my Apple Watch, I can speak text to display and I send it to the LEDVest to display. If I am annoyed at a stop light, I tend to keep it safe. e.g. “Smog sucks”.  So far the software periodically displays the temperature from the hardware, along with the WTI price and Canadian currency via the yahoo finance API. If I loose connectivity to the iPhone, the arduino portion fails-safe and displays the stop symbol and posts the temperature every 30 seconds.

I’ll talk about the implementation details later.