Post not yet marked as solved
The status codes returned for REST API queries give a good indication of the issue encountered. Generally:
200 is good
400 means you've passed in bad or incomplete parameters
401 is an authentication issue
However, there's a parameter validation inconsistency on the availability endpoint.
If you pass in out-of-range coordinates to the weather endpoint, you get the expected 400 response code.
But if you pass bad coordinates to the availability endpoint, it blows up and returns a 500 (internal server error).
I've got code that can deal with this response, but it would be much better to know exactly where the problem lies. 500 tells me there's an issue on the server that's out of my control...
I have gone through several tutorials for WeatherKit. But my sample app doesn't return weather data. The following is a list of what I have.
I've registered a Bundle ID for my sample app with the WeatherKit capability on.
I've created a developer profile for my sample app.
I've opened my Xcode project to make sure that the WeatherKit capability is enabled.
I have run my sample app with an actual device.
I have waited for more than 30 minutes for the service to kick in. It's been several days.
The following is my code.
import SwiftUI
import CoreLocation
import WeatherKit
struct ContentView: View {
@State var currentWeather: CurrentWeather?
var body: some View {
NavigationStack {
List {
Group {
SampleCell(title: "Temperature", value: String(currentWeather?.apparentTemperature.value ?? 0.0) + "℃")
SampleCell(title: "Cloud coverage", value: String(currentWeather?.cloudCover ?? 0.0))
SampleCell(title: "Weather condition", value: String(currentWeather?.condition.description ?? ""))
SampleCell(title: "Dew point", value: String(currentWeather?.dewPoint.value ?? 0.0) + "℃")
SampleCell(title: "Humidity", value: String(currentWeather?.humidity ?? 0.0))
SampleCell(title: "Pressure", value: String(currentWeather?.pressure.value ?? 0.0) + "mbar")
SampleCell(title: "Pressure trend", value: String(currentWeather?.pressureTrend.description ?? ""))
SampleCell(title: "Temperature", value: String(currentWeather?.temperature.value ?? 0.0) + "℃")
SampleCell(title: "UV index", value: String(currentWeather?.uvIndex.value ?? 0))
SampleCell(title: "Visibility", value: String(currentWeather?.visibility.value ?? 0.0) + "m")
}
SampleCell(title: "Window direction", value: String(currentWeather?.wind.direction.value ?? 0.0) + "°")
SampleCell(title: "Window speed", value: String(currentWeather?.wind.speed.value ?? 0.0) + "km/h")
SampleCell(title: "Gust", value: String(currentWeather?.wind.gust?.value ?? 0.0) + "km/h")
}
.navigationTitle(Text("CurrentWeather"))
.task {
let service = WeatherService()
let location = CLLocation(
latitude: 35.467081,
longitude: 139.620798
)
do {
let weather = try await service.weather(for: location)
currentWeather = weather.currentWeather
} catch let error {
print(error.localizedDescription)
}
}
}
}
}
struct SampleCell: View {
var title: String
var value: String
var body: some View {
VStack {
HStack {
Text(title)
Spacer()
Text(value)
}
}
}
}
Yet, I constantly get the following warnings.
2023-11-29 09:33:46.504737+0900 WeatherCrazyMama[15279:9734572] [WeatherDataService] Aborting silent interpolation: no interpolator object; location=CLLocationCoordinate2D(latitude: 35.467081, longitude: 139.620798)
2023-11-29 09:33:47.900605+0900 WeatherCrazyMama[15279:9734577] [AuthService] Failed to generate jwt token for: com.apple.weatherkit.authservice with error: Error Domain=WeatherDaemon.WDSJWTAuthenticatorServiceListener.Errors Code=2 "(null)"
2023-11-29 09:33:47.989603+0900 WeatherCrazyMama[15279:9734572] [WeatherService] Encountered an error when fetching weather data subset; location=<+35.46708100,+139.62079800> +/- 0.00m (speed -1.00 mps / course -1.00) @ 2023/11/29 9:33:46 AM Japan Standard Time, error=WeatherDaemon.WDSJWTAuthenticatorServiceListener.Errors 2 Error Domain=WeatherDaemon.WDSJWTAuthenticatorServiceListener.Errors Code=2 "(null)"
The operation couldn’t be completed. (WeatherDaemon.WDSJWTAuthenticatorServiceListener.Errors error 2.)
What am I doing wrong? Thanks.
Post not yet marked as solved
Hello, I'm using WeatherKit in a project to display the SF Symbol for the weather in the app toolbar. I have this for the WeatherModel:
import Foundation
import WeatherKit
@MainActor class WeatherManager: ObservableObject {
@Published var weather: Weather?
public func getWeather() async {
do {
weather = try await Task.detached(priority: .userInitiated) {
return try await WeatherService.shared.weather(for: .init(latitude: 28.3772, longitude: -81.5707))
}.value
} catch {
fatalError("\(error)")
}
}
var symbol: String {
weather?.currentWeather.symbolName ?? "xmark.icloud.fill"
}
var temp: String {
let temp =
weather?.currentWeather.temperature
let convert = temp?.converted(to: .fahrenheit).description
return convert ?? ""
}
}
And this in the SwiftUI View:
ToolbarItem(placement: .topBarLeading) {
@ObservedObject var weatherManager = WeatherManager()
Image(systemName: weatherManager.symbol)
.task {
await weatherManager.getWeather()
}
}
But when I build and run the app on my phone it displays the "xmark.icloud.fill" instead of the actual weather.
Did I do something wrong?
Post not yet marked as solved
I'm trying to make a PHP implementation to fetch data from the WeatherKit REST API.
When using jwt.io to create a JWT, everything works correctly, so my keys, identifiers, etc. are set up correctly.
When using jtw.io to verify my own generated JWT, the header and payload are correct, but "Invalid Signature" is displayed.
The file path for the private key exists and the file is loaded correctly.
My PHP code:
function generate_jwt(): String {
$tmpFilePath = realpath(dirname(__FILE__)).'/';
$filePath = $tmpFilePath.'../AuthKey.pem';
//$filePath = $tmpFilePath.'../AuthKey.p8';
$private_key = NULL;
if (file_exists($filePath)) {
$private_key = file_get_contents($filePath);
}
$header = [
"alg" => "ES256",
"kid" => "XXXXXXXXXX",
"id" => "YYYYYYYYYY.com.thing.stuff",
"typ" => "JWT"
];
$header = $this->base64_url_encode(json_encode($header));
$issuedAt = time();
$payload = [
"iat" => $issuedAt,
"exp" => $issuedAt + 30,
"iss" => "YYYYYYYYYY",
"sub" => "com.thing.stuff"
];
$payload = $this->base64_url_encode(json_encode($payload));
$signature = $this->base64_url_encode(hash_hmac('sha256', "$header.$payload", $private_key, true));
$jwt = "$header.$payload.$signature";
return $jwt;
}
function base64_url_encode($text): String {
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($text));
}
Any ideas?
When retrieving data using WeatherKit, a CLLocation is passed. What is the range / span of that data? In other words: at what distance to the given location is the returned weather data valid?
Post not yet marked as solved
In my app I retrieve the daily weather for a location via the REST API. This works fine in almost all cases. However, for October 29th (yesterday) it returns a 404 Not Found error. This is an example request that fails:
https://weatherkit.apple.com/api/v1/weather/en/48.1582271841334/11.5418646663957?dataSets=forecastDaily&dailyStart=2023-10-28T22:00:00.0000000Z&dailyEnd=2023-10-29T22:00:00.0000000Z
I have also tried to append the timezone &timezone=Europe/Berlin - but the problem persists.
Maybe it has to do with the fact that Daylight saving time ended yesterday at the location requested (Germany)? It certainly looks like a bug. Where can I report it if this isn't the right place to do so?
Using WeatherKit I want to get a 5-day forecast starting tomorrow,
however, I only get 4 elements in the forecast.
What am I missing here?
public func updateWeather()async{
guard locationManager.location != nil else {locationManager.updateLocation(); return}
if self.needsUpdating{
let startOfToday = Calendar.current.startOfDay(for: Date())
let endOfToday = startOfToday+24*3600
let firstDay:Date = endOfToday+1
let lastDay:Date = firstDay+(5*24*3600)
futureWeather = try? await WeatherService.shared.weather(for: locationManager.location!,
including: .daily(startDate: firstDay, endDate: lastDay)
)
}
}
Post not yet marked as solved
Is there a means of accessing historical averages from WeatherKit? I imagine it would be monthly averages.
Apple's Weather app recently introduced "Averages" – both daily and monthly. I'm wondering if this data is derived from WeatherKit. I'm also curious if there exists an API available to developers that hasn't made its way into the documentation yet, or if there are plans for making "averages" available to developers in upcoming improvements to WeatherKit.
Post not yet marked as solved
This is a app for weather in which i used weatherkit.I have added "privacy - Location when in Usage Description in info of project and also enabled location in features of simulator to Apple.After doing all this ,still the permission message for location is not appearing in app in simulator.Following is my code:
import CoreLocation
import UIKit
//final means this class will not be subclassed
final class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
//to access weather data
let service = WeatherService()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
getUserLocation()
}
func getUserLocation(){
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func getWeather(location : CLLocation){
//asynchoronus task
Task {
do {
//if it throws error
//await tells to wait until function gives results
let result = try await service.weather(for: location)
print("Current : "+String(describing: result.currentWeather))
print("Daily : "+String(describing: result.dailyForecast))
print("Hourly : "+String(describing: result.hourlyForecast))
} catch {
//it will be excecuted
print(error.localizedDescription)
}
}
}
func setupView(){
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else {
return
}
locationManager.stopUpdatingLocation()
getWeather(location: location)
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .denied:
print("location permission denied")
case .authorizedWhenInUse, .authorizedAlways :
manager.startUpdatingLocation()
print("Location Permission Granted")
case .notDetermined :
print("location Permission not determined")
default:
break
}
}
}
Post not yet marked as solved
I created my own service to generate a JWT for WeatherKit. When I use this JWT in Postman it works as expected.
However, if I use it in my React application I get a 403 CORS pre-flight check error. What this essentially means is by nature, Safari - before doing the GET call with Authorization header - it does a preflight check OPTIONS call without headers, to check if the service will accept the request. Unfortunately this generates a 403 error instead of an 200, so the GET Call with Authorization header cannot be made.
Is this by design to prevent webfrontends from accessing the API or is this a bug I encountered? Thank you!
Post not yet marked as solved
Hi,
We have been using DarkSky's API for a few years now and we've always been able to pull data for at least 3 years prior to the current date.
With WeatherKit, we are seeing that data is only available for the last 2 years. I've seen a few posts confirming this, but I'm curious if we will always be limited to 2 years of data or if this is a temporary situation and as time goes on, WeatherKit will have more and more historical data available? Another way to put it is will Apple always delete any data older than 2 years or will they start to build up an archive so in 10 years from now, they will have 12 total years of data (given they have 2 years right now).
Thanks!
Post not yet marked as solved
My app has been using WeatherKit via its REST API for months with success. Suddenly, the weatherkit API only returns to me "reason" : "NOT_ENABLED" now.
I am unsure why it is suddenly telling me WeatherKit is not enabled?
Post not yet marked as solved
System status shows WeatherKit as available, but currently all calls returns status 401 with the response body containing {"reason": "NOT_ENABLED"}.
We have been running the exact same code in production since March 2023. Nothing changed. The system just started returning errors.
Is that happening for anyone else?
Post not yet marked as solved
I've received a forecast with non-zero precipitationChance and zero precipitationIntensity. Is this expected? How should I interpret the data?
{
"forecastStart": "2023-09-02T02:00:00Z",
"cloudCover": 0.55,
"conditionCode": "PartlyCloudy",
"daylight": false,
"humidity": 0.92,
"precipitationAmount": 0,
"precipitationIntensity": 0,
"precipitationChance": 0.31,
"precipitationType": "clear",
"pressure": 1017.56,
"pressureTrend": "steady",
"snowfallIntensity": 0,
"snowfallAmount": 0,
"temperature": 12.56,
"temperatureApparent": 12.22,
"temperatureDewPoint": 11.26,
"uvIndex": 0,
"visibility": 23505.2,
"windDirection": 233,
"windGust": 6.17,
"windSpeed": 2.82
}
Post not yet marked as solved
Could somebody please point me to the project download mentioned in Novall Khan’s “Meet Weatherkit” presentation?
I’d additionally or alternatively be interested in any working examples for using the rest API, eg in Python, to access Weatherki.
thanks,
Rob
Post not yet marked as solved
What is the highest level of location precision achievable with the WeatherKit API? When latitude and longitude are given up to the fifth decimal place, the precision is around 1 meter. Could this ever be more accurate than providing the lat/long to the fourth decimal place, which has a precision of about 10 meters?
Post not yet marked as solved
Can it be done?
I can reliably crash Xcode by attempting the following in a playground:
import UIKit
import WeatherKit
import CoreLocation
let sanFrancisco = CLLocation(latitude: 37.7749, longitude: 122.4194)
let weatherService = WeatherService()
let weather = try await weatherService.weather(for: sanFrancisco)
let temperature = weather.currentWeather.temperature
print(temperature)
Xcode 14.3.1
macOS 13.4.1
Post not yet marked as solved
Hello - migrated from darksky to WeatherKit in April of this year. With some difficulty finally got the REST API to work via the following resources:
https://developer.apple.com/weatherkit/get-started/
which is horribly inadequate for JWT instructions. So i also used:
https://dev.iachieved.it/iachievedit/weatherkit-rest-api/
which was quite helpful.
As stated, in April i managed to get this working. About a week ago it stopped working.
The response from my calls are 401 Unauthorized in the header and { "reason": "NOT_ENABLED" } in the body.
I believe the key i created expired and thus WeatherKit stopped responding. So i tried to re-enable access using the same Apple key and a new JWT signature. That did not seem to work, so i removed the old key and created a new one. Downloaded the p8 file and used openssl on my ubuntu server to create pem and pub files for the jwt token. Still nothing. I have tried almost all combinations of keys and ID #s in the JWT.io console that i can think of.
Importantly, nowhere in the official Apple documentation does it say what parameters the key creation and expiry dates can be. Does the key creation date have to match the date the key was created in Apple Developer Console??? What expiry dates are valid???? No idea.
I have submitted a code level request, but they punted me to feedback which apparently does nothing. Still no resolution, nor have i been contacted once by an Apple representative. This is what my $200 developer fee gets me?! Unacceptable.
If anyone has any idea on how to resolve this issue and/or create valid jwt tokens easier (via PHP preferably), i'm all ears.
Thanks, airyt
Post not yet marked as solved
I am trying to format a measurement in my application as described in this documentation.
Notice the example code:
let temp = Measurement<UnitTemperature>(value: 38, unit: .celsius)
let formattedTemp = temp.formatted(.measurement(width: .wide, usage: .weather, numberFormat: .numeric(precision: .fractionLength(1))))
// For locale: en_US: 100.4 degrees Fahrenheit
When I try to do the same, I receive the following errors:
Cannot infer contextual base in reference to member 'fractionLength'
Cannot infer contextual base in reference to member 'numeric'
Extra argument 'numberFormat' in call
My code is as follows:
Text("\(current.temperature.formatted(.measurement(width: .wide, usage: .weather, numberFormat: .numeric(precision: .fractionLength(1)))))")
Where current is a CurrentWeather type provided by WeatherKit.
Why is my adherence to the documentation causing these errors?
Post not yet marked as solved
https://weatherkit.apple.com/api/v1/weather/English/23.0685/72.6535
is the attempt that we are making. Is there anything wrong with the URL /