Syntax for getting precipitationChance?

I'm getting my feet wet with weatherKit and have managed to get all the current weather I need with the code below.

My app requires one more thing - the chance of precipitation in the next 0-20 minutes or so - in order to close the windows if the odds exceed some threshold.

I haven't been able to find a single code example of retrieving the forecasted rain odds. It looks like the number I need will be in the MinuteWeather contained? in the HourlyForecast but it's completely a mystery to me how to extract what I need. I need a trail of breadcrumbs!

I tried getting the hourly and daily forecasts but the value I'm looking for isn't there.

    import Foundation
    import WeatherKit

    @Observable class WeatherManager {

    private let weatherService = WeatherService()
    var weather: Weather?

    func getWeather(lat: Double, long: Double) async {
        do {
            weather = try await Task.detached(priority: .userInitiated) { [weak self] in
                return try await self?.weatherService.weather(for: .init(latitude: lat, longitude: long))
            }.value
        } catch {
            print("Failed to get weather data. \(error)")
        }
        print("\(weather)")
        
        do {
            let daily = try await weatherService.weather(for: .init(latitude: lat, longitude: long), including: .daily)
            let hourly = try await weatherService.weather(for: .init(latitude: lat, longitude: long), including: .hourly)
            print("Daily: \(daily)")
            print("Hourly: \(hourly)")
        } catch let error {
            print("Failed to get the forecast. \(error)")
        }
    }   // close getWeather function
    
    var icon: String {
        guard let iconName = weather?.currentWeather.symbolName else { return "--" }
        
        return iconName
    }
    
    var temperature: String {
        guard let temp = weather?.currentWeather.temperature else { return "--" }
        let convert = temp.converted(to: .fahrenheit).value
        
        return String(Int(convert)) + "°F"
    }
    
    var humidity: String {
        guard let humidity = weather?.currentWeather.humidity else { return "--" }
        let computedHumidity = humidity * 100
        
        return String(Int(computedHumidity)) + "%"
    }
    var pressure: String {
        guard let press = weather?.currentWeather.pressure else { return "--" }
        let convertP = press.converted(to: UnitPressure.inchesOfMercury).value
        return String((convertP)) + " in. Hg"
    }
    var UVindex: String {
        guard let uv = weather?.currentWeather.uvIndex.value else { return "--" }
        return "\(uv)" + " index"
    }
    
    var POP: String {
    ????
        return String(Int(chance)) + "%"
    }
}

Replies

I did it! The key learning for me was to "include .minute" in the weather query and to then receive back an array of minute-by-minute data. You can then step thru the forecast array and pick out the data you need, in my case the precipitationChance.

Successful code:

import Foundation
import WeatherKit

@Observable class WeatherManager {

    private let weatherService = WeatherService()
    var weather: CurrentWeather?
    var forcast: Forecast<MinuteWeather>?
    var pop: [Double] = []   // Will build this array with precipitationChance for each minute forward

    func getWeather(lat: Double, long: Double) async {
        do {
            let weatherFetch = try await weatherService.weather(for: .init(latitude: lat, longitude: long), including: .current, .minute)
            weather = weatherFetch.0   // The current weather
            forcast = weatherFetch.1   // The forecast by minute for the next hour or so
            var i: Int = -1
                forcast?.forEach { weatherEntry in   // This loop loads the precipitationChance values into the pop array
                    i = i + 1
                    let timer = DateFormatter.localizedString(from: weatherEntry.date, dateStyle: .short, timeStyle: .short)
                    pop.append(weatherEntry.precipitationChance)
                    print("Time \(i):  \(timer) = \(pop[i])")   // Time and printing are for debugging
                }
        } catch let error {
            print("Failed to get the weather and/or forecast. \(error)")
        }
    }   // close getWeather function
    
    var icon: String {
        guard let iconName = weather?.symbolName else { return "--" }
        return iconName
    }
    
    var temperature: String {
        guard let temp = weather?.temperature else { return "--" }
        let convert = temp.converted(to: .fahrenheit).value
        return String(Int(convert)) + "°F"
    }
    
    var humidity: String {
        guard let humidity = weather?.humidity else { return "--" }
        let computedHumidity = humidity * 100
        return String(Int(computedHumidity)) + "%"
    }
    
    var pressure: String {
        guard let press = weather?.pressure else { return "--" }
        let convertP = press.converted(to: UnitPressure.inchesOfMercury).value
        return String((convertP)) + " in. Hg"
    }
    
    var UVindex: String {
        guard let uv = weather?.uvIndex.value else { return "--" }
        return "\(uv)" + " index"
    }
    
    var POP: String {
        if pop.count > 11 {    // Check that there are at least 11 minutes of forecast data
            var chance = pop[10] * 100.0   //  Report the forecast for the (arbitrary) 11th entry
            return String(Int(chance)) + "%"
        } else {
            return "--"
        }
    }
}