Skip to main content
Version: Next

Data

Overview

SDK fetches data from the server and caches it locally automatically.

FetchConfig and SkyPath.shared.dataHistoryTime determine the data types and history time to be fetched from the server.

A corresponding SkyPathDelegate function is called when new data is fetched from the server.

Query data with a specific configuration to get data from local storage.

H3 resolution 5 is used by SkyPath for the turbulence reports area.

Offline First

The SDK is offline first. All tracked turbulence data is stored offline until successfully sent to the server, and the fetched data from the server is stored on the disk and accessible offline according to the description below. All configurations are stored on the disk and stay across app launches until an explicit change.

Fetch Config

At first request, the whole data according to SkyPath.shared.fetchConfig is fetched and then only the new data that appeared (delta) is fetched to save network traffic. When cached data expires or a delta can't be received, the whole fresh data will be received again.

There are thousands of turbulence reports around the globe. To reduce network traffic usage and keep only data that is currently needed, the data fetch is separated into the different types controlled by the SkyPath.shared.fetchConfig object that is set initially to default values and can be updated at any time. All of the below are optional to set, but recommended due to your specific flow.

SkyPath.shared.fetchConfig is read-only. To change it, use updateFetchConfig(_:) to mutate the current config, or setFetchConfig(_:) to replace it entirely. Both validate the new config and throw a QueryError on a malformed polygon or viewport, or on an unsupported aircraftICAO, so call them with try.

After updating the fetch config in any way, the check, if needed to fetch new data, will be made. If the change requires a new server fetch, the server request will be made immediately.

You can update the fetch config at any time. When updating just one field, use one call.

try SkyPath.shared.updateFetchConfig { $0.types = [.observations] }

When updating multiple fields, prefer to change them all inside a single updateFetchConfig closure. On any fetch config update the SDK will check if it needs to update the data, for example, because the polygon has been updated. Updating the fetch config multiple times immediately could result in a situation where you will not get fresh data immediately, but in the next fetch cycle, in a minute or so.

try SkyPath.shared.updateFetchConfig {
$0.types = [.observations]
$0.polygon = somePolygon
}

To replace the whole config in one go, use setFetchConfig(_:).

try SkyPath.shared.setFetchConfig(FetchConfig(polygon: somePolygon))
info

Updating the fetch config will trigger a fetch from the server if needed automatically. Receiving server response will take some time, so SkyPathDelegate callbacks will be called with a delay, not immediately after the update. Delegate callbacks will not be called if no new server fetch is needed or no new data will be received.

tip

Update the visible data by querying the SDK after updating the fetch config, not waiting for the SkyPathDelegate. SDK caches data locally, so querying after the fetch config update will return cached data if any. Then, update data again in the SkyPathDelegate callback.

Route Corridor (Polygon)

The route corridor polygon is a geo-fence area to fetch data inside only. It should be a valid GeoJSON Polygon RFC 7946. Use your route line coordinates to create a polygon with some width distance (50-150 NM is good).

SDK will fetch all data in the corridor at first, and then only the delta since the previous fetch in this corridor. When changing the corridor to a different then all data will be fetched in the new corridor (not delta) and then will use delta again. So the route corridor should change only when the route line changes. Choose the corridor width according to your needs because a bigger width and a bigger corridor will consume more network traffic.

warning

A bigger width of corridor consumes more network traffic.

It is fetched separately from other data types as fast as possible, and also stored offline. Stored on disk, accessible offline.

let polygon: [CLLocationCoordinate2D] = []
try SkyPath.shared.updateFetchConfig { $0.polygon = polygon }

Route PolygonRoute Polygon

According to GeoJSON Polygon RFC 7946 it should be a closed ring with the last coordinate equal to the first, and have at least 4 coordinates; otherwise, updateFetchConfig(_:) throws a QueryError.invalidPolygon.

The SDK provides helpers to build the corridor from your route line and to simplify a complex polygon.

// build a 100 NM wide corridor around the route line
let corridor = routeWaypoints.geodesic.buffer(widthNM: 100)
try SkyPath.shared.updateFetchConfig { $0.polygon = corridor }

// or simplify an existing polygon
try SkyPath.shared.updateFetchConfig { $0.polygon = polygon.simplify(tolerance: 0.1) }

geodesic expands waypoints into great circle route coordinates. buffer(widthNM:simplify:tolerance:) simplifies the result by default with a tolerance of 0.1, which is good for a server fetch. Use 0.01 when drawing the corridor on the map.

Alternatively, set route and routeWidth in the fetch config and let the SDK build the corridor.

try SkyPath.shared.updateFetchConfig {
$0.route = routeWaypoints.geodesic
$0.routeWidth = 100
}

route should be great circle route coordinates, not just waypoints.

Viewport

A viewport is a polygon of a visible map area in the app to fetch the right data when it's needed. Please keep in mind, that the SDK will try to fetch the data for the viewport as soon as possible after updating FetchConfig.viewport. So, to save network traffic, consider updating viewport when it's needed.

All data in the viewport will be fetched at first, and then a delta will be fetched only. But when changing a viewport, all data will be fetched again.

warning

Frequent changes and a bigger viewport consume more network traffic.

A good place could be when the pilot moved the map manually, released the finger, and the map stopped moving after animation, or when the focused map area is moved by code far from the previously focused area. Stored on disk, accessible offline.

let polygon: [CLLocationCoordinate2D] = []
try SkyPath.shared.updateFetchConfig { $0.viewport = polygon }

Route PolygonRoute Polygon

The simplest viewport polygon would be a currently visible rectangle on the map, like [NorthWest, NorthEast, SouthEast, SouthWest, NorthWest]. For a more complex polygon, the following rules are applied.

Should be a closed ring with at least 4 coordinates, otherwise updateFetchConfig(_:) throws a QueryError.invalidPolygon. Use Array<CLLocationCoordinate2D>.simplify(tolerance:) to simplify a complex viewport polygon and reduce network traffic.

warning

For performance and network optimization, the SDK could fetch the viewport differently. See details below.

The viewport will be one of the following types inside the SDK based on its size. Separation is done inside the SDK automatically. The Continental United States area is used to illustrate the approximate size as 1x.

  • Small - less than 0.5x
  • Small-Medium - 0.5x
  • Medium - 1x
  • Large - more than 2x
  • All severities are fetched.
  • The whole viewport is fetched.

Viewport SmallRoute Polygon

tip

Hide the smooth severity on the map on the corresponding zoom level which depends on the map library, so we provided the Continental US area as a reference for the viewport area.

History Time

Set DataHistoryTime to fetch data for. It's an enum with cases: halfHour, hour, twoHours and fourHours. The default is twoHours. The server does some data precalculations so only the specified time frames are supported.

SkyPath.shared.dataHistoryTime = .twoHours

When initialized, the SDK fetches the history selected by dataHistoryTime, and then receives only the updates since the last update.

It determines the data history to be fetched from the server. So if it is set to .twoHours for example (the default one), there will be no data locally available for more than 2 hours. If need 4 hours of history, set SkyPath.dataHistoryTime to .fourHours.

Changing from lower time to higher will require an API request to fetch data, when changing from higher to lower time, data could be available immediately as it was already included in the higher history time fetch. Alternatively, time can be set to .fourHours once to fetch 4 hours of history data always and then just query with a different time history to show on the map. Please note, that it will increase network traffic but will allow having more data available immediately and offline during changing time history.

Update

Data is updated every 1 minute.

When the fetch config route polygon or the viewport is changed, they are fetched as fast as possible not waiting for the next time interval.

You can temporarily disable new data fetch from the server or disable it only when the app is in the background.

// disable data fetch
SkyPath.shared.isFetchEnabled = false

// disable data fetch in background
SkyPath.shared.isBackgroundFetchEnabled = false

Can be updated at any time in the project. Value is stored across app launches until changed.

When you change some fetch config parameters SDK will start fetching fresh data immediately if needed.

warning

There is no way to trigger a fetch manually. The SDK fetches on its own schedule and re-evaluates whenever the fetch config changes, so a "refresh data" button or pull-to-refresh is not supported.

It could be helpful to know if SkyPath data was updated a long time ago (when offline for example), so check when the last time data was successfully received from the server.

SkyPath.shared.dataUpdatedAt
info

Implement SkyPathDelegate.didFail(with:dataType:) to monitor if there is any error and handle it accordingly. Its dataType carries the failing DataType for data fetch errors and is nil for everything else.

Stop Fetching

The preferred way to stop data fetching is to set SkyPath.shared.isFetchEnabled = false.

Based on your implementation you can use other options:

  • Set FetchConfig.types to an empty set:
try SkyPath.shared.updateFetchConfig {
$0.types = []
$0.viewportTypes = []
}
  • Remove the polygon, and viewport in the fetch config. It can stop fetching because no area is set to fetch data in.

SDK will continue recording and reporting data.

info

Removing a flight by SkyPath.setFlight(nil) does not stop fetching data because SDK allows fetching data without it, for example for a map visible viewport.

Data Types

SkyPath provides different data types, see DataType. FetchConfig.types is a Set<DataType> and the default is observations only. Set it if you need more than just observations data.

try SkyPath.shared.updateFetchConfig { $0.types = [.observations] }

Set<DataType> provides a set(type:enabled:) convenience to toggle a single type while keeping the rest.

try SkyPath.shared.updateFetchConfig { $0.types.set(type: .oneLayer, enabled: true) }

FetchConfig.viewportTypes controls what is fetched inside the viewport. By default it follows types. Use it to avoid loading a heavy data type for a huge area on a low map zoom level.

try SkyPath.shared.updateFetchConfig { $0.viewportTypes = [.observations] }

FetchConfig.altRange limits the fetched altitudes, measured in feet. The default is 0...52000.

It no longer needs to be round to a thousand feet — QueryError.altRangeNotRoundToThousandFeet was removed in 4.0. SkyPath stores data in 1,000 ft altitude blocks, so each bound is mapped to the block containing it and then clamped to 0...52000. A bound of 39,500 therefore resolves to the 39,000..<40,000 block, and the effective range can be slightly wider than the values you pass. Pass round thousands when you need the range to match exactly.

Turbulence Severity

H3H3

Color Legend

The SDK does not provide colors. Define your own in the app; the following is the reference palette used by SkyPath.

Smooth #FFFFFF (alpha 0.6) Border #898989 (alpha 0.8)
Light #FFF04C (alpha 0.8)
Light-Moderate #FFBC09 (alpha 0.8)
Moderate #FF7100 (alpha 0.8)
Moderate-Occasionally Severe #FF0000 (alpha 0.8)

By default, all severities of turbulence will be fetched, but you can provide a minimum severity to fetch.

try SkyPath.shared.updateFetchConfig { $0.minSev = .moderate }

TurbulenceSeverity has five cases: smooth, light, lightModerate, moderate and moderateSevere. TurbulenceSeverity.smooth severity means that the pilot who crossed this hexagon didn't experience any turbulence, so his report is smooth. Each hexagon can have multiple reports left for it because multiple flights crossed this hexagon. By default, ObservationsQuery has aggregate = true which means you'll get one ObservationsItem per hexagon with the most severe report for this hexagon.