Lucid Weather Clock — developing open source hyper-local weather app with precipitation clock in Swift

Wojciech Rutkowski
iOS App Development
8 min readDec 17, 2015

--

I decided to build an iOS app that will show me whether it will rain or not in the neighbourhood.

In the following posts I’ll describe my process of creating the app from the scratch to submission.

I was inspired by my colleague

’s after-hours work: http://weatherclock.matthewcanty.co.uk and wanted to build similar solution for Apple devices.

Setup

The app will be available on iPhones and iPads running iOS 9 and later. I’ll use CocaPods as a dependency manager.
While browsing the Internet I’m starring projects on Github that I find on different blogs, newsletters and CocoaControls catalogue. Currently I have almost 300 starred repos and the point is to let me use them in future project.. which Lucid Weather Clock actually is 🎉

What tools I need? Networking for fetching weather data, some parser for the data as well. The best choice for networking will be Alamofire, but let me search for SDKs for Forecast.io which data I’m going to use. I have found two libraries written in Swift:

At first I liked Peter’s more, but gave a try both and finally decided to go with Satyam’s implementation. The good thing is that I no longer need networking framework and objects, that’s all covered by ForecastIO.

I need a clean looking, minimalist clock, let’s use CocoaControls again. Bang, here it is: BEMAnalogClock — highly customisable and nice looking — a good starting point.

BEMAnalogClock sample screen shot from https://github.com/Boris-Em/BEMAnalogClock

I’ll have to add rain probability overlays to the clock. Longer for more rain and less opaque for more rain probability. I had been thinking to tweak layers of clock, but why not use charts: radar/spider or pie sounds perfect for the solution. Here is the great charts framework I’ve used before: ios-charts 🤓

I’ll also need to know user location to display hyper-local forecast. It’s easy to use Apple’s API, but I remember I have a starred library — location manager called INTULocationManager.

CocoaPods

To sum up this is the current Podfile:

Basic UI

It’s time to run pod install and having fun in the storyboard.
I placed UIView on the middle of the view, attaching both sides with 16pt margin, centre vertically with fixed ratio 1:1 — all in all clock should be a circle 🕑

I added UIView under clock and pinned with centre horizontally and vertically with clock together with equal height and width — a ghost view for chart.

Below I put UIButton and UILabel. UIButton will refresh the forecast from the current location and time. UILabel will show last update time together with last update address. UIButton is attached to bottom-right corner with margins 16pt and UILabel is attached 10pt trailing to UIButton, 16pt leading and 16pt bottom. UIActivityIndicatorView is pinned to UIButton similarly to chart view to clock view.

On the middle top I placed UILabel showing current temperature.

Storyboard — basic design

Flow

First of all I need to think about the flow within the app. User enters the app, the app tries to get user location, then asks ForecastIO about weather in that location, then displays current temperature, adjusts colours and draws a graph representing precipitation in the next hour minute by minute.

There are three app modes then:

  • loading mode
  • presentation mode
  • refresh mode

In the loading mode I will run the clock high speed and backward 🕣. It should be a nice effect that attract attention while the app localise the user and fetches the data. Additionally temperature label and refresh button will be hidden and info label will be empty. Background colour will be light grey.

I will make transition to presentation mode with clock animation with setting current time, showing chart with fade, setting temperature, adjusting background colour and updating info label. Asynchronously I’ll run reverse geocode user’s location and when available I’ll add address to the info label.

Refresh mode is similar to the loading mode, but I won’t set background back to light grey and I won’t hide the temperature.

I need to handle bunch of errors: location not available, internet connection not available, forecast data not available, minute-by-minute data not available ❌.

Coding Time (Clock Time?)

I created a template that will represent my flow in ViewController:

I’ll focus on the main functionality for now. I need to locate the user, so since iOS 8 I need a key NSLocationWhenInUseUsageDescription in a plist (more here: http://nshipster.com/core-location-in-ios-8/). I choose when in use, because the app will fetch forecast data only on user’s request.

Then INTULocationManager in locateUser function:

#1 I’m requesting with .Neighbourhood which is equivalent to 1000 meters or better and received within last 5 minutes. For weather data it should be enough accuracy, but it’s worth testing .Block which is 100 meters or better and received within last 1 minute. Timeout is set to 5 seconds as I don’t want the user waits for the data too long.

#2 In case of success I’m saving the location and requesting the forecast data. Asynchronously I’m requesting an address from location.

#3 On different location service related errors the app will display an alert informing the user so that he can check the location permissions

Resolving location to address lives in fetchGeoData function:

Simple call to CLGeocoder 🏡 — on success I’m saving the place mark and calling updateInfo().

It’s time for ForecastIO to play with:

I’m requesting the data from the Forecast API with just received location. On error I’m displaying the message so that the user know and I’m enabling refresh button to let user try again. When forecast data is available the app #1 updates the info label and calls adjustDesignToWeather which will set the temperature label, adjust colour and chart. Then #2 stops the animation and let user refresh the data when needed.

Now handling the info label updates. Label should be empty after app starts up, then it should contain time and, if available, address:

The app should run at that state, but besides last update info I won’t be able to see anything else. Temperature can be good for start, let’s do this and run the app ⛏:

First run: last updated date with address and.. temperature is available!

It’s not perfect you may say… well, it’s true 🎉

Tweaking Design

Firstly I’ll start by adjusting the clock, then I’ll focus on objects appearance and animations so that the feel of the app is good. Last step in this point is to change background colour based on the temperature. Yay!

Basic stuff, I’m setting background on the app to light gray, setting initial values of UILabels, etc. clockDisplayedToken is used to animate fade of the clock for longer only after the app starts. I have also set clock’s delegate to ViewController, so that I can implement graduation length (the longest stripes every 15 minutes, shorter every 5 minutes and small for others). Additionally there is configureWatchface function which changes length of clock hands and background colour:

It’s time to run the app again:

Yes, that’s better!

On refresh I need to hide clock, chart and seconds’ hand for nicer animation. I’ll start animation by calling clockLoadingTick described below.

Clock’s animation, huh? I will update the clock very frequently with older times each time. I decided to go with 0.01 refresh rate #2 and -30 seconds step #1. I tried different combinations and this seems to give the best effect. clockLoadingTick is running in loop calling via performSelector itself. Break flag is clockLoadingAnimationActive, which is set to false after receiving forecast data — in that case I’m setting the clock to 12 o’clock with animation and after animation is done #3 I’m showing seconds’ hand and setting clock to show current time with ticking. #4 is prepared for chart, which should be visible as well.

Last thing in this step is coloured background according to the temperature. I’ve created ColorManager with static function convertTemperatureToColor. I’m using two models ColorMapSegment which is used to build colorMap and Color which consist of 3 colour values: red, green, blue and helper computed var toUIColor used later.

Main colours were picked manually from colour picker to fit nice with white UI details and resemble the temperature. Converter walks through colour map trying to fit temperature into the ranges. If the temperature is above or beyond min and max edges the colour stays the same. For ranges between two main colours it is calculated pro rata.

And I’m using it in adjustDesignToWeather just below temperature label setting:

Current state of the application looks like this:

Chart

It’s the time 🕑 to create the main purpose of the app: showing precipitation in the next hour. Firstly I need to setup chart view to suits my needs: clear background, no legend, no descriptions, no values and hole displayed. I had to rotate the chart as by default 0 started at 90° which is not very convenient for clock. I’m using Pie Chart where each data is one minute period with custom length and colour - more precisely different alpha of white.

To present the precipitation data on the chart I’ll make sure that we have data to present and then I’ll map it to easy to use model ForecastDataEntry:

then I’ll prepare data for Charts library:

Intensity of precipitation is limited to 0.9 #1. It’s just to make the chart looks nicer. Model is created in #2. Time from Forecast.io comes from current minute minutely to now + 1 hour. ios-charts don’t like to get data with unsorted order, hence sorting #3. Loop through sorted data creates ChartDataEntry with strange looking value 0.01666666667 which is 6/360° → 1 minute. I used data property to pass intensity of the precipitation. Next I’m creating array of colours — white with alpha value equal to precipitation probability #5. This array will be used by Charts library. Last thing is to create xVals — in my case minutes #6 and provide everything as PieChartData to chart.

Summary

I described my way of creation simple weather application that perfectly suits my needs. I have few ideas how to improve the app:

  • 12 hour precipitation with 3D Touch or long press on older devices
  • sharing current weather situation with square picture of clock with chart below on background with colour adjusted to the temperature
  • horizontal layout with temperature and clock side by side
  • geeky data available with funny taps combination 🤓

Any comments and questions are highly welcome!

I’m going to write about implementing above improvements in the next posts.

Project is open sourced and available on GitHub Lucid Weather Clock 👏

You can follow me on Twitter: @WojRutkowski and Medium.

Next part Lucid Weather Clock — part 2: 3D Touch, 12 hour precipitation and shake-to-share is available here.

--

--

Wojciech Rutkowski
iOS App Development

iOS Developer from London | Creator of Owlery — mobile educational app that teaches kids English