This is part of a series of posts related to My Internet of Things and MobileFirst adventure. An index to all posts can be found at the end of the first post.
Ok, I know I’m getting really carried away on this thing now, but I got an Apple Watch and thought it might be kinda cool to see if I could create a Watch app for my doorbell app.
I’m going to focus on the unique challenges I ran into for this app and not get too deep into how you build a Watch app. There are resources out there (although not as many as I had hoped) to teach you how. One particularly good resource I purchased is a tutorials book from Ray Wenderlich called “watchOS 2 by Tutorials“. This is definitely worth the price of admission if you are serious about learning how to build for the Watch. One caution I will leave you with – make sure whatever resources you are using are for WatchOS 2. There were significant changes between version 1 and version 2 and there is still quite a bit of WatchOS 1 info out there.
There are three features of the Doorbell app I would consider making available on the Watch. Well, actually, there are really only three features in the whole Doorbell app:
- Push notifications when someone rings the doorbell.
- Displaying a picture from the Raspberry Pi
- Displaying video from the Raspberry Pi
It didn’t take me long to see that #3 is a long shot. There are very few video viewing apps for the Watch and those that do exist provide the video content as files transferred to the Watch. I considered rearchitecting things to capture short video clips to files that could be sent to the Watch, but I pretty quickly wrote that off. I’ll focus on Push notifications and pictures.
A Watch app is not a separate app at all. It is really an extension of the iPhone app. A Watch app cannot exist without its “host” iPhone app. You get started by adding a Watch target to your existing iPhone app.
Display a picture
My plan was to put a button on a Watch interface that would request a picture from the iPhone app and would then display it in a WKInterfaceGroup or something. Creating the UI was pretty easy – there are a lot fewer options than on iOS.
The WatchConnectivity package gives you various ways to communicate between the iPhone and the Apple Watch. Interfaces can be immediate (sendMessage) or background (transferFile, updateApplicationContext). My first instinct was that I wanted it immediately so I should use sendMessage. This actually did work, but sendMessage has a size limit on the payload. I never did fine an authoritative source that defined the specific value, but unless I really reduced the resolution on my picture, I exceeded it.
So, I took the approach to have the Watch request the picture using updateApplicationContext. The iOS app would then send the takePicture command to the Raspberry Pi, receive the picture in packets, reassemble it, then send it to the Watch using transferFile. This actually worked brilliantly – as long as the iOS app was in the foreground.
This is where I ran into another constraint from Apple. The iOS app is VERY limited in what it can do when in the background. Namely, it can only use the network for vary limited reasons. Publishing MQTT commands doesn’t seem to be one of them. There are other ways to do this. You can have an iOS app do some network operations if you can justify classifying it as a VOIP or News app. Then it can do some http operations in the background. I’m sure that’s how Watch apps such as weather apps get regular updates from the host app.
Nonetheless, I did get something to work as long as the iOS app is active. I can get a picture from my Raspberry Pi to the Watch.
Push notifications on the Apple Watch
I learned that there is an involved set of rules that determines when a Push notification shows up on the Watch and when it shows up on the iPhone, even if you have built in the ability to handle the Push on the Watch. You don’t get to choose – iOS makes the decision. Basically, the notification will always go to the iPhone if it is not locked and asleep. Even if it is, the Watch must be on your wrist before iOS will decide to let the Watch present the notification. Makes sense I guess. Why would you want a notification to show up on your Watch if you have the iPhone in your hand and you are looking at it?
The Watch app has an ExtensionDelegate class which is analogous to the AppDelegate of the iPhone app. You override the method handleActionWithIdentifier to handle the custom action buttons (Picture and Video) I created in the AppDelegate class. Now when the doorbell is pressed, Node-RED on the Raspberry Pi will send a request to the IBM Push Notifications service which will in turn have APNS send a push. If the iPhone is asleep in my pocket, I will get a Push notice on the Watch with the Picture and Video buttons.
The problem is, what do I do now that I have received the Push on my Watch? Since I already found that I can’t ask the iPhone app to go get me a picture and then update it on the Watch, I am kinda stuck. I did end up implementing Handoff so once I tap either Video or Picture on the Watch, I can slide up on the lock screen icon on my iPhone and have it take me directly to the corresponding view and refresh it.
So as it turns out, the Apple Watch probably isn’t the ideal platform for a visual doorbell app. But it was an interesting experiment. At this point, I think I have milked this adventure for all it is worth.
Well, it has been quite an adventure. I can’t say that I have a terribly useful app at the end of all this, but it did give me a platform to learn a lot of stuff.
If you are interested, the full code for the project can be found in GitHub.