My {darksky} package has been around for years, now, and the service that powers it was purchased by Apple before the pandemic. The DarkSky API is slated to be shuttered in December of this year and is being replaced by Apple’s WeatherKit xOS Framework and REST API.
I’ve started work on a {weatherkit} package which uses the WeatherKit REST API. You’ll need an Apple Developer account and will also need to setup some items in said account, and locally so you can authenticate to the API. Once all the authentication bits are setup, it’s pretty easy to get the weather data:
wx <- wxkit_weather(43.2683199, -70.8635506)
wx <- wx_tidy(wx)
str(wx)
## List of 4
## $ currentWeather :List of 18
## ..$ name : chr "CurrentWeather"
## ..$ metadata :List of 8
## .. ..$ attributionURL: chr "https://weather-data.apple.com/legal-attribution.html"
## .. ..$ expireTime : POSIXct[1:1], format: "2022-07-07 12:28:07"
## .. ..$ latitude : num 43.3
## .. ..$ longitude : num -70.9
## .. ..$ readTime : POSIXct[1:1], format: "2022-07-07 12:23:07"
## .. ..$ reportedTime : POSIXct[1:1], format: "2022-07-07 10:48:55"
## .. ..$ units : chr "m"
## .. ..$ version : int 1
## ..$ asOf : POSIXct[1:1], format: "2022-07-07 12:23:07"
## ..$ cloudCover : num 0.29
## ..$ conditionCode : chr "MostlyClear"
## ..$ daylight : logi TRUE
## ..$ humidity : num 0.68
## ..$ precipitationIntensity: num 0
## ..$ pressure : num 1018
## ..$ pressureTrend : chr "rising"
## ..$ temperature : num 19.5
## ..$ temperatureApparent : num 19.4
## ..$ temperatureDewPoint : num 13.5
## ..$ uvIndex : int 2
## ..$ visibility : num 29413
## ..$ windDirection : int 50
## ..$ windGust : num 12
## ..$ windSpeed : num 4.42
## $ forecastDaily :List of 3
## ..$ name : chr "DailyForecast"
## ..$ metadata:List of 8
## .. ..$ attributionURL: chr "https://weather-data.apple.com/legal-attribution.html"
## .. ..$ expireTime : POSIXct[1:1], format: "2022-07-07 13:23:07"
## .. ..$ latitude : num 43.3
## .. ..$ longitude : num -70.9
## .. ..$ readTime : POSIXct[1:1], format: "2022-07-07 12:23:07"
## .. ..$ reportedTime : POSIXct[1:1], format: "2022-07-07 10:48:55"
## .. ..$ units : chr "m"
## .. ..$ version : int 1
## ..$ days :'data.frame': 10 obs. of 26 variables:
## .. ..$ forecastStart : POSIXct[1:10], format: "2022-07-07 04:00:00" "2022-07-08 04:00:00" "2022-07-09 04:00:00" "2022-07-10 04:00:00" ...
## .. ..$ forecastEnd : POSIXct[1:10], format: "2022-07-08 04:00:00" "2022-07-09 04:00:00" "2022-07-10 04:00:00" "2022-07-11 04:00:00" ...
## .. ..$ conditionCode : chr [1:10] "PartlyCloudy" "PartlyCloudy" "MostlyClear" "MostlyClear" ...
## .. ..$ maxUvIndex : int [1:10] 7 7 7 8 7 6 7 4 5 4
## .. ..$ moonPhase : chr [1:10] "firstQuarter" "firstQuarter" "waxingGibbous" "waxingGibbous" ...
## .. ..$ moonrise : POSIXct[1:10], format: "2022-07-07 17:38:12" "2022-07-08 18:50:47" "2022-07-09 20:07:35" "2022-07-10 21:27:35" ...
## .. ..$ moonset : POSIXct[1:10], format: "2022-07-07 04:32:48" "2022-07-08 04:54:51" "2022-07-09 05:20:27" "2022-07-10 05:51:50" ...
## .. ..$ precipitationAmount: num [1:10] 0 0.49 0 0 0 1.32 0.24 3.44 5.07 8.35
## .. ..$ precipitationChance: num [1:10] 0.01 0.15 0.07 0 0.07 0.39 0.37 0.4 0.47 0.44
## .. ..$ precipitationType : chr [1:10] "clear" "rain" "clear" "clear" ...
## .. ..$ snowfallAmount : num [1:10] 0 0 0 0 0 0 0 0 0 0
## .. ..$ solarMidnight : POSIXct[1:10], format: "2022-07-07 04:48:29" "2022-07-08 04:48:39" "2022-07-09 04:48:49" "2022-07-10 04:48:58" ...
## .. ..$ solarNoon : POSIXct[1:10], format: "2022-07-07 16:48:26" "2022-07-08 16:48:35" "2022-07-09 16:48:44" "2022-07-10 16:48:53" ...
## .. ..$ sunrise : POSIXct[1:10], format: "2022-07-07 09:10:59" "2022-07-08 09:11:42" "2022-07-09 09:12:26" "2022-07-10 09:13:11" ...
## .. ..$ sunriseCivil : POSIXct[1:10], format: "2022-07-07 08:36:06" "2022-07-08 08:36:53" "2022-07-09 08:37:41" "2022-07-10 08:38:31" ...
## .. ..$ sunriseNautical : POSIXct[1:10], format: "2022-07-07 07:50:45" "2022-07-08 07:51:39" "2022-07-09 07:52:36" "2022-07-10 07:53:34" ...
## .. ..$ sunriseAstronomical: POSIXct[1:10], format: "2022-07-07 06:55:17" "2022-07-08 06:56:30" "2022-07-09 06:57:46" "2022-07-10 06:59:04" ...
## .. ..$ sunset : POSIXct[1:10], format: "2022-07-08 00:25:50" "2022-07-09 00:25:26" "2022-07-10 00:24:59" "2022-07-11 00:24:30" ...
## .. ..$ sunsetCivil : POSIXct[1:10], format: "2022-07-08 01:00:39" "2022-07-09 01:00:10" "2022-07-10 00:59:38" "2022-07-11 00:59:04" ...
## .. ..$ sunsetNautical : POSIXct[1:10], format: "2022-07-08 01:46:01" "2022-07-09 01:45:23" "2022-07-10 01:44:42" "2022-07-11 01:43:58" ...
## .. ..$ sunsetAstronomical : POSIXct[1:10], format: "2022-07-08 02:41:14" "2022-07-09 02:40:16" "2022-07-10 02:39:14" "2022-07-11 02:38:09" ...
## .. ..$ temperatureMax : num [1:10] 25.8 28.7 24.9 25.4 28.9 ...
## .. ..$ temperatureMin : num [1:10] 13.7 16.3 14.8 12.2 12.4 ...
## .. ..$ daytimeForecast :'data.frame': 10 obs. of 11 variables:
## .. .. ..$ forecastStart : POSIXct[1:10], format: "2022-07-07 11:00:00" "2022-07-08 11:00:00" "2022-07-09 11:00:00" "2022-07-10 11:00:00" ...
## .. .. ..$ forecastEnd : POSIXct[1:10], format: "2022-07-07 23:00:00" "2022-07-08 23:00:00" "2022-07-09 23:00:00" "2022-07-10 23:00:00" ...
## .. .. ..$ cloudCover : num [1:10] 0.39 0.45 0.33 0.11 0.42 0.69 0.39 0.95 0.87 0.88
## .. .. ..$ conditionCode : chr [1:10] "PartlyCloudy" "PartlyCloudy" "MostlyClear" "Clear" ...
## .. .. ..$ humidity : num [1:10] 0.57 0.58 0.54 0.47 0.49 0.63 0.64 0.71 0.7 0.66
## .. .. ..$ precipitationAmount: num [1:10] 0 0.31 0 0 0 0.26 0.17 3.15 0.22 1.37
## .. .. ..$ precipitationChance: num [1:10] 0 0.09 0.04 0 0.02 0.29 0.16 0.31 0.33 0.3
## .. .. ..$ precipitationType : chr [1:10] "clear" "rain" "clear" "clear" ...
## .. .. ..$ snowfallAmount : num [1:10] 0 0 0 0 0 0 0 0 0 0
## .. .. ..$ windDirection : int [1:10] 155 263 122 237 231 228 219 98 39 62
## .. .. ..$ windSpeed : num [1:10] 8.73 9.42 7.42 6.23 9.75 ...
## .. ..$ overnightForecast :'data.frame': 10 obs. of 11 variables:
## .. .. ..$ forecastStart : POSIXct[1:10], format: "2022-07-07 23:00:00" "2022-07-08 23:00:00" "2022-07-09 23:00:00" "2022-07-10 23:00:00" ...
## .. .. ..$ forecastEnd : POSIXct[1:10], format: "2022-07-08 11:00:00" "2022-07-09 11:00:00" "2022-07-10 11:00:00" "2022-07-11 11:00:00" ...
## .. .. ..$ cloudCover : num [1:10] 0.49 0.5 0.15 0.37 0.46 0.4 0.88 0.91 0.8 NA
## .. .. ..$ conditionCode : chr [1:10] "PartlyCloudy" "PartlyCloudy" "MostlyClear" "MostlyClear" ...
## .. .. ..$ humidity : num [1:10] 0.78 0.78 0.71 0.73 0.69 0.81 0.83 0.85 0.84 NA
## .. .. ..$ precipitationAmount: num [1:10] 0.06 0.11 0 0 0 1.11 0.04 2.26 6.47 NA
## .. .. ..$ precipitationChance: num [1:10] 0.05 0.07 0.01 0.02 0.1 0.27 0.24 0.31 0.31 NA
## .. .. ..$ precipitationType : chr [1:10] "rain" "rain" "clear" "clear" ...
## .. .. ..$ snowfallAmount : num [1:10] 0 0 0 0 0 0 0 0 0 NA
## .. .. ..$ windDirection : int [1:10] 192 341 347 223 218 242 276 13 49 NA
## .. .. ..$ windSpeed : num [1:10] 9.92 7.15 6.59 5.52 10.95 ...
## .. ..$ restOfDayForecast :'data.frame': 10 obs. of 11 variables:
## .. .. ..$ forecastStart : POSIXct[1:10], format: "2022-07-07 12:23:07" NA NA NA ...
## .. .. ..$ forecastEnd : POSIXct[1:10], format: "2022-07-08 04:00:00" NA NA NA ...
## .. .. ..$ cloudCover : num [1:10] 0.47 NA NA NA NA NA NA NA NA NA
## .. .. ..$ conditionCode : chr [1:10] "PartlyCloudy" NA NA NA ...
## .. .. ..$ humidity : num [1:10] 0.6 NA NA NA NA NA NA NA NA NA
## .. .. ..$ precipitationAmount: num [1:10] 0 NA NA NA NA NA NA NA NA NA
## .. .. ..$ precipitationChance: num [1:10] 0.01 NA NA NA NA NA NA NA NA NA
## .. .. ..$ precipitationType : chr [1:10] "clear" NA NA NA ...
## .. .. ..$ snowfallAmount : num [1:10] 0 NA NA NA NA NA NA NA NA NA
## .. .. ..$ windDirection : int [1:10] 163 NA NA NA NA NA NA NA NA NA
## .. .. ..$ windSpeed : num [1:10] 9.7 NA NA NA NA NA NA NA NA NA
## $ forecastHourly :List of 3
## ..$ name : chr "HourlyForecast"
## ..$ metadata:List of 8
## .. ..$ attributionURL: chr "https://weather-data.apple.com/legal-attribution.html"
## .. ..$ expireTime : POSIXct[1:1], format: "2022-07-07 13:23:07"
## .. ..$ latitude : num 43.3
## .. ..$ longitude : num -70.9
## .. ..$ readTime : POSIXct[1:1], format: "2022-07-07 12:23:07"
## .. ..$ reportedTime : POSIXct[1:1], format: "2022-07-07 10:48:55"
## .. ..$ units : chr "m"
## .. ..$ version : int 1
## ..$ hours :'data.frame': 243 obs. of 20 variables:
## .. ..$ forecastStart : POSIXct[1:243], format: "2022-07-07 02:00:00" "2022-07-07 03:00:00" "2022-07-07 04:00:00" "2022-07-07 05:00:00" ...
## .. ..$ cloudCover : num [1:243] 0.02 0.01 0.02 0.31 0.44 0.74 0.3 1 0.96 0.32 ...
## .. ..$ conditionCode : chr [1:243] "Clear" "Clear" "Clear" "MostlyClear" ...
## .. ..$ daylight : logi [1:243] FALSE FALSE FALSE FALSE FALSE FALSE ...
## .. ..$ humidity : num [1:243] 0.74 0.78 0.81 0.83 0.86 0.88 0.9 0.92 0.88 0.83 ...
## .. ..$ precipitationAmount : num [1:243] 0 0 0 0 0 0 0 0 0 0 ...
## .. ..$ precipitationIntensity: num [1:243] 0 0 0 0 0 0 0 0 0 0 ...
## .. ..$ precipitationChance : num [1:243] 0 0 0 0 0 0 0 0 0 0 ...
## .. ..$ precipitationType : chr [1:243] "clear" "clear" "clear" "clear" ...
## .. ..$ pressure : num [1:243] 1014 1015 1016 1016 1016 ...
## .. ..$ pressureTrend : chr [1:243] "rising" "rising" "rising" "rising" ...
## .. ..$ snowfallIntensity : num [1:243] 0 0 0 0 0 0 0 0 0 0 ...
## .. ..$ temperature : num [1:243] 18.3 17 16.3 15.7 14.9 ...
## .. ..$ temperatureApparent : num [1:243] 18.2 16.9 16.1 15.5 14.7 ...
## .. ..$ temperatureDewPoint : num [1:243] 13.6 13.1 12.9 12.8 12.6 ...
## .. ..$ uvIndex : int [1:243] 0 0 0 0 0 0 0 0 0 1 ...
## .. ..$ visibility : num [1:243] 28105 26514 24730 23883 23669 ...
## .. ..$ windDirection : int [1:243] 315 302 315 308 310 298 307 316 319 6 ...
## .. ..$ windGust : num [1:243] 2.93 2.56 2.92 3.25 3.35 ...
## .. ..$ windSpeed : num [1:243] 2.93 2.56 2.92 3.25 3.35 3.09 3.51 2.91 2.36 4.55 ...
## $ forecastNextHour:List of 6
## ..$ name : chr "NextHourForecast"
## ..$ metadata :List of 9
## .. ..$ attributionURL: chr "https://weather-data.apple.com/legal-attribution.html"
## .. ..$ expireTime : POSIXct[1:1], format: "2022-07-07 13:23:07"
## .. ..$ language : chr "en-US"
## .. ..$ latitude : num 43.3
## .. ..$ longitude : num -70.9
## .. ..$ providerName : chr "US National Weather Service"
## .. ..$ readTime : POSIXct[1:1], format: "2022-07-07 12:23:07"
## .. ..$ units : chr "m"
## .. ..$ version : int 1
## ..$ summary :'data.frame': 1 obs. of 4 variables:
## .. ..$ startTime : POSIXct[1:1], format: "2022-07-07 12:24:00"
## .. ..$ condition : chr "clear"
## .. ..$ precipitationChance : num 0
## .. ..$ precipitationIntensity: num 0
## ..$ forecastStart: POSIXct[1:1], format: "2022-07-07 12:24:00"
## ..$ forecastEnd : POSIXct[1:1], format: "2022-07-07 13:45:00"
## ..$ minutes :'data.frame': 81 obs. of 3 variables:
## .. ..$ startTime : POSIXct[1:81], format: "2022-07-07 12:24:00" "2022-07-07 12:25:00" "2022-07-07 12:26:00" "2022-07-07 12:27:00" ...
## .. ..$ precipitationChance : num [1:81] 0 0 0 0 0 0 0 0 0 0 ...
## .. ..$ precipitationIntensity: num [1:81] 0 0 0 0 0 0 0 0 0 0 ...
The wx_tidy()
function, for now, only does date-time string conversion to POSIXct
objects, but it may do more in the future.
It doesn’t appear that historical weather data is available, yet, so you’re limited to using the API to get daily and hourly conditions and forecasts for the present plus some days. As such, I’ve focused a bit on some helper functions to show current conditions and forecasts in the R console/stdout:
current_conditions(wx)
## Weather for (43.268, -70.864) as of 2022-07-07 08:23:07
##
## Conditions: Mostly Clear
## Temperature: 67.08°F
## Feels like: 66.92°F
## Dew Point: 56.28°F
## Wind: 2.7 mph (NE)
## Pressure: 1017.68 mb (rising)
## Visibility: 18 miles
## UV Index: 🟩 2 (Low)
##
## https://weather-data.apple.com/legal-attribution.html
hourly_forecast(wx)
## Weather forecast for (43.268, -70.864) as of 2022-07-07 08:23:07
##
## Today @ 09:00 │ 🌡 69°F │ 💦 63% │ 1018 mb — │ 😎 │ Mostly Clear │ 🟨
## @ 10:00 │ 🌡 71°F │ 💦 58% │ 1018 mb — │ 😎 │ Mostly Clear │ 🟨
## @ 11:00 │ 🌡 74°F │ 💦 55% │ 1018 mb — │ 😎 │ Mostly Clear │ 🟧
## @ 12:00 │ 🌡 75°F │ 💦 53% │ 1017 mb — │ 😎 │ Partly Cloudy │ 🟧
## @ 13:00 │ 🌡 77°F │ 💦 51% │ 1017 mb ↓ │ 😎 │ Partly Cloudy │ 🟧
## @ 14:00 │ 🌡 78°F │ 💦 50% │ 1016 mb ↓ │ 😎 │ Partly Cloudy │ 🟧
## @ 15:00 │ 🌡 78°F │ 💦 50% │ 1016 mb ↓ │ 😎 │ Partly Cloudy │ 🟨
## @ 16:00 │ 🌡 77°F │ 💦 52% │ 1016 mb ↓ │ 😎 │ Partly Cloudy │ 🟨
## @ 17:00 │ 🌡 76°F │ 💦 55% │ 1015 mb ↓ │ 😎 │ Partly Cloudy │ 🟩
## @ 18:00 │ 🌡 75°F │ 💦 58% │ 1015 mb — │ 😎 │ Partly Cloudy │ 🟩
## @ 19:00 │ 🌡 73°F │ 💦 62% │ 1015 mb — │ 😎 │ Mostly Clear │ 🟩
## @ 20:00 │ 🌡 70°F │ 💦 67% │ 1015 mb — │ 😎 │ Partly Cloudy │ 🟩
## @ 21:00 │ 🌡 68°F │ 💦 71% │ 1015 mb — │ 🌕 │ Mostly Cloudy │ 🟩
## @ 22:00 │ 🌡 67°F │ 💦 74% │ 1015 mb — │ 🌕 │ Mostly Cloudy │ 🟩
## @ 23:00 │ 🌡 67°F │ 💦 74% │ 1015 mb — │ 🌕 │ Mostly Cloudy │ 🟩
## Fri @ 00:00 │ 🌡 66°F │ 💦 74% │ 1015 mb — │ 🌕 │ Partly Cloudy │ 🟩
## @ 01:00 │ 🌡 65°F │ 💦 78% │ 1015 mb — │ 🌕 │ Partly Cloudy │ 🟩
## @ 02:00 │ 🌡 64°F │ 💦 81% │ 1015 mb — │ 🌕 │ Mostly Clear │ 🟩
## @ 03:00 │ 🌡 63°F │ 💦 83% │ 1015 mb — │ 🌕 │ Partly Cloudy │ 🟩
## @ 04:00 │ 🌡 62°F │ 💦 85% │ 1015 mb — │ 🌕 │ Partly Cloudy │ 🟩
##
## https://weather-data.apple.com/legal-attribution.html
Note that the attribution is required by Apple.
I’ll likely add a daily forecast console printer soon.
There are a few helper functions in the package for value conversion between unit systems, iconifying some values, and working with time zones. {weatherkit} uses lutz::tz_lookup_coords()
in places to auto-determine the time zone from lat/lng pairs, and also includes a function to intuit lat/lng from an IP address using ipapi (they have a generous free tier).
As of the timestamp on this blog post, Apple’s WeatherKit provides up to 500,000 API calls a month per Apple Developer Program membership. If you need additional API calls, monthly subscription plans will be available for purchase sometime after the beta is officially over. This is the expected pricing:
- 500,000 calls/month: Included with membership
- 1 million calls/month: US$ 49.99
- 2 million calls/month: US$ 99.99
- 5 million calls/month: US$ 249.99
- 10 million calls/month: US$ 499.99
- 20 million calls/month: US$ 999.99
Apple’s WeatherKit documentation consistently says “Apple Developer Program membership”, which seems to indicate you need to give them money every year to use the REST API. We’ll see if that’s truly the case after the service leaves beta status.
FIN
Kick the tyres & drop issues/PRs as one may be wont to do.
Saying The Quiet Part Out Loud On Juneteenth
I realize you have to be living under a rock in the U.S. to not know that yesterday, was Juneteenth (a portmanteau of “June Nineteenth”). Still, I feel compelled to explain that said date marks the day when federal troops arrived in Galveston, Texas in 1865 to take control of the state and ensure that all enslaved people be freed. (See, Texas has always been kinda horrible when it comes to basic human decency). The arrival of said troops came ~2.5 years after the signing of the Emancipation Proclamation. The day honors the end to slavery in the United States.
GreyNoise (my employer) — like an increasing number of organizations in the U.S. — observes Juneteenth as a company-wide holiday, and I’ll be spending part of today pondering that word, “end”, in the last sentence of the previous paragraph.
There are two major political parties in the U.S. and one just decided, this past Juneteenth weekend, we no longer need the Voting Rights Act of 1965. March 7th of that year was a Sunday, known today as “Bloody Sunday” (it turns out there have been far too many of those kinds of Sundays). It was a day when Alabama state troopers beat & whipped voting rights advocates with nightsticks, and also used chemical weapons on them, in an effort to keep in place discriminatory practices that were extensively used to prevent African Americans from exercising their right to vote.
The act banned literacy tests for voting, required federal oversight over voter registration in areas where less than 50 percent of the non-white population had registered to vote, and authorized the U.S. attorney general to investigate the use of poll taxes in state and local elections. (In 1964, the 24th Amendment made poll taxes illegal in federal elections; poll taxes in state elections were banned in 1966 by the U.S. Supreme Court.)
I’m fairly certain (~95%) — regardless of the party in power — we’ll see the current Supreme Court overturn the state poll tax decision within the next 5-10 years (thankfully, constitutional amendments are a bit harder to wipe way). You can definitely say goodbye to the voting rights act if Republicans gain control of Congress and especially if they regain Congress and the POTUS seat.
Both of those events will make it possible for ~21 states to become even more evil than they already are, and set the stage for a few, awful decades.
I know gas is expensive.
I know food is more expensive than ever.
I know some shelves are bare.
I know lines are longer.
I know we’re still in a pandemic.
I also know that I don’t want to see the devolution of America back to when it was so “great” that we cheered on police when they were treating innocent, peaceful citizens like armed, enemy combatants, and ensured the reign of evil men by making it impossible for large swaths of Americans to vote.
In the fall of 2022 and fall of 2024, we’ll know if we, as a nation, care more about convenience than conscience.
Which side of Juneteenth will you be on when the time comes to choose the path forward?