diff --git a/bun.lock b/bun.lock index c9151d8..3a785f4 100644 --- a/bun.lock +++ b/bun.lock @@ -17,10 +17,24 @@ "name": "@aris/core", "version": "0.0.0", }, + "packages/aris-data-source-weatherkit": { + "name": "@aris/data-source-weatherkit", + "version": "0.0.0", + "dependencies": { + "@aris/core": "workspace:*", + "arktype": "^2.1.0", + }, + }, }, "packages": { "@aris/core": ["@aris/core@workspace:packages/aris-core"], + "@aris/data-source-weatherkit": ["@aris/data-source-weatherkit@workspace:packages/aris-data-source-weatherkit"], + + "@ark/schema": ["@ark/schema@0.56.0", "", { "dependencies": { "@ark/util": "0.56.0" } }, "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA=="], + + "@ark/util": ["@ark/util@0.56.0", "", {}, "sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA=="], + "@oxfmt/darwin-arm64": ["@oxfmt/darwin-arm64@0.24.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aYXuGf/yq8nsyEcHindGhiz9I+GEqLkVq8CfPbd+6VE259CpPEH+CaGHEO1j6vIOmNr8KHRq+IAjeRO2uJpb8A=="], "@oxfmt/darwin-x64": ["@oxfmt/darwin-x64@0.24.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-vs3b8Bs53hbiNvcNeBilzE/+IhDTWKjSBB3v/ztr664nZk65j0xr+5IHMBNz3CFppmX7o/aBta2PxY+t+4KoPg=="], @@ -57,6 +71,10 @@ "@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="], + "arkregex": ["arkregex@0.0.5", "", { "dependencies": { "@ark/util": "0.56.0" } }, "sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw=="], + + "arktype": ["arktype@2.1.29", "", { "dependencies": { "@ark/schema": "0.56.0", "@ark/util": "0.56.0", "arkregex": "0.0.5" } }, "sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ=="], + "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], "oxfmt": ["oxfmt@0.24.0", "", { "dependencies": { "tinypool": "2.0.0" }, "optionalDependencies": { "@oxfmt/darwin-arm64": "0.24.0", "@oxfmt/darwin-x64": "0.24.0", "@oxfmt/linux-arm64-gnu": "0.24.0", "@oxfmt/linux-arm64-musl": "0.24.0", "@oxfmt/linux-x64-gnu": "0.24.0", "@oxfmt/linux-x64-musl": "0.24.0", "@oxfmt/win32-arm64": "0.24.0", "@oxfmt/win32-x64": "0.24.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-UjeM3Peez8Tl7IJ9s5UwAoZSiDRMww7BEc21gDYxLq3S3/KqJnM3mjNxsoSHgmBvSeX6RBhoVc2MfC/+96RdSw=="], diff --git a/packages/aris-data-source-weatherkit/.env.example b/packages/aris-data-source-weatherkit/.env.example new file mode 100644 index 0000000..fee8994 --- /dev/null +++ b/packages/aris-data-source-weatherkit/.env.example @@ -0,0 +1,4 @@ +WEATHERKIT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" +WEATHERKIT_KEY_ID=ABC123DEFG +WEATHERKIT_TEAM_ID=TEAM123456 +WEATHERKIT_SERVICE_ID=com.example.weatherkit.test diff --git a/packages/aris-data-source-weatherkit/README.md b/packages/aris-data-source-weatherkit/README.md new file mode 100644 index 0000000..5aabe5f --- /dev/null +++ b/packages/aris-data-source-weatherkit/README.md @@ -0,0 +1,58 @@ +# @aris/data-source-weatherkit + +Weather data source using Apple WeatherKit REST API. + +## Usage + +```typescript +import { WeatherKitDataSource, Units } from "@aris/data-source-weatherkit" + +const dataSource = new WeatherKitDataSource({ + credentials: { + privateKey: "-----BEGIN PRIVATE KEY-----\n...", + keyId: "ABC123", + teamId: "DEF456", + serviceId: "com.example.weatherkit", + }, + hourlyLimit: 12, // optional, default: 12 + dailyLimit: 7, // optional, default: 7 +}) + +const items = await dataSource.query(context, { + units: Units.metric, // or Units.imperial +}) +``` + +## Feed Items + +The data source returns four types of feed items: + +| Type | Description | +| ----------------- | -------------------------- | +| `weather-current` | Current weather conditions | +| `weather-hourly` | Hourly forecast | +| `weather-daily` | Daily forecast | +| `weather-alert` | Weather alerts | + +## Priority + +Base priorities are adjusted based on weather conditions: + +- Severe conditions (tornado, hurricane, blizzard, etc.): +0.3 +- Moderate conditions (thunderstorm, heavy rain, etc.): +0.15 +- Alert severity: extreme=1.0, severe=0.9, moderate=0.75, minor=0.7 + +## Authentication + +WeatherKit requires Apple Developer credentials. Generate a private key in the Apple Developer portal under Certificates, Identifiers & Profiles > Keys. + +## Validation + +API responses are validated using [arktype](https://arktype.io) schemas. + +## Generating Test Fixtures + +To regenerate fixture data from the real API: + +1. Create a `.env` file with your credentials (see `.env.example`) +2. Run `bun run scripts/generate-fixtures.ts` diff --git a/packages/aris-data-source-weatherkit/fixtures/san-francisco.json b/packages/aris-data-source-weatherkit/fixtures/san-francisco.json new file mode 100644 index 0000000..f4b1f77 --- /dev/null +++ b/packages/aris-data-source-weatherkit/fixtures/san-francisco.json @@ -0,0 +1,6457 @@ +{ + "generatedAt": "2026-01-17T00:37:11.971Z", + "location": { "lat": 37.7749, "lng": -122.4194 }, + "response": { + "currentWeather": { + "name": "CurrentWeather", + "metadata": { + "attributionURL": "https://developer.apple.com/weatherkit/data-source-attribution/", + "expireTime": "2026-01-17T00:42:11Z", + "latitude": 37.77, + "longitude": -122.42, + "readTime": "2026-01-17T00:37:11Z", + "reportedTime": "2026-01-17T00:37:11Z", + "units": "m", + "version": 1, + "sourceType": "modeled" + }, + "asOf": "2026-01-17T00:37:11Z", + "cloudCover": 0.18, + "cloudCoverLowAltPct": 0.18, + "cloudCoverMidAltPct": 0.18, + "cloudCoverHighAltPct": 0.18, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.62, + "precipitationIntensity": 0, + "pressure": 1017.74, + "pressureTrend": "steady", + "temperature": 15.87, + "temperatureApparent": 14.43, + "temperatureDewPoint": 8.6, + "uvIndex": 0, + "visibility": 30655.28, + "windDirection": 352, + "windGust": 17.67, + "windSpeed": 11.15 + }, + "forecastDaily": { + "name": "DailyForecast", + "metadata": { + "attributionURL": "https://developer.apple.com/weatherkit/data-source-attribution/", + "expireTime": "2026-01-17T01:37:11Z", + "latitude": 37.77, + "longitude": -122.42, + "readTime": "2026-01-17T00:37:11Z", + "reportedTime": "2026-01-16T23:05:34Z", + "units": "m", + "version": 1, + "sourceType": "modeled" + }, + "days": [ + { + "forecastStart": "2026-01-16T08:00:00Z", + "forecastEnd": "2026-01-17T08:00:00Z", + "conditionCode": "Clear", + "maxUvIndex": 3, + "moonPhase": "waningCrescent", + "moonrise": "2026-01-16T14:09:55Z", + "moonset": "2026-01-16T23:12:47Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-16T08:19:22Z", + "solarNoon": "2026-01-16T20:19:43Z", + "sunrise": "2026-01-16T15:23:30Z", + "sunriseCivil": "2026-01-16T14:54:53Z", + "sunriseNautical": "2026-01-16T14:22:43Z", + "sunriseAstronomical": "2026-01-16T13:51:16Z", + "sunset": "2026-01-17T01:16:09Z", + "sunsetCivil": "2026-01-17T01:44:43Z", + "sunsetNautical": "2026-01-17T02:16:53Z", + "sunsetAstronomical": "2026-01-17T02:48:20Z", + "temperatureMax": 19.88, + "temperatureMin": 8.85, + "windGustSpeedMax": 18.66, + "windSpeedAvg": 5.57, + "windSpeedMax": 11.53, + "daytimeForecast": { + "forecastStart": "2026-01-16T15:00:00Z", + "forecastEnd": "2026-01-17T03:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "humidity": 0.63, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 19.88, + "temperatureMin": 9.02, + "windDirection": 6, + "windGustSpeedMax": 18.66, + "windSpeed": 5.6, + "windSpeedMax": 11.53 + }, + "overnightForecast": { + "forecastStart": "2026-01-17T03:00:00Z", + "forecastEnd": "2026-01-17T15:00:00Z", + "cloudCover": 0.13, + "conditionCode": "MostlyClear", + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 12.51, + "temperatureMin": 8.03, + "windDirection": 11, + "windGustSpeedMax": 18.52, + "windSpeed": 10.23, + "windSpeedMax": 11.28 + }, + "restOfDayForecast": { + "forecastStart": "2026-01-17T00:37:11Z", + "forecastEnd": "2026-01-17T08:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "humidity": 0.77, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 15.87, + "temperatureMin": 9.84, + "windDirection": 348, + "windGustSpeedMax": 18.52, + "windSpeed": 10.36, + "windSpeedMax": 11.15 + } + }, + { + "forecastStart": "2026-01-17T08:00:00Z", + "forecastEnd": "2026-01-18T08:00:00Z", + "conditionCode": "MostlyCloudy", + "maxUvIndex": 2, + "moonPhase": "waningCrescent", + "moonrise": "2026-01-17T14:56:53Z", + "moonset": "2026-01-18T00:13:04Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-17T08:19:42Z", + "solarNoon": "2026-01-17T20:20:03Z", + "sunrise": "2026-01-17T15:23:07Z", + "sunriseCivil": "2026-01-17T14:54:34Z", + "sunriseNautical": "2026-01-17T14:22:26Z", + "sunriseAstronomical": "2026-01-17T13:51:01Z", + "sunset": "2026-01-18T01:17:12Z", + "sunsetCivil": "2026-01-18T01:45:42Z", + "sunsetNautical": "2026-01-18T02:17:50Z", + "sunsetAstronomical": "2026-01-18T02:49:14Z", + "temperatureMax": 16.94, + "temperatureMin": 8.03, + "windGustSpeedMax": 20.39, + "windSpeedAvg": 10.06, + "windSpeedMax": 11.3, + "daytimeForecast": { + "forecastStart": "2026-01-17T15:00:00Z", + "forecastEnd": "2026-01-18T03:00:00Z", + "cloudCover": 0.71, + "conditionCode": "MostlyCloudy", + "humidity": 0.69, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 16.94, + "temperatureMin": 8.04, + "windDirection": 29, + "windGustSpeedMax": 20.39, + "windSpeed": 10.63, + "windSpeedMax": 11.3 + }, + "overnightForecast": { + "forecastStart": "2026-01-18T03:00:00Z", + "forecastEnd": "2026-01-18T15:00:00Z", + "cloudCover": 0.84, + "conditionCode": "MostlyCloudy", + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 13.41, + "temperatureMin": 9.08, + "windDirection": 31, + "windGustSpeedMax": 14.86, + "windSpeed": 8.91, + "windSpeedMax": 10.05 + } + }, + { + "forecastStart": "2026-01-18T08:00:00Z", + "forecastEnd": "2026-01-19T08:00:00Z", + "conditionCode": "MostlyClear", + "maxUvIndex": 3, + "moonPhase": "waningCrescent", + "moonrise": "2026-01-18T15:37:11Z", + "moonset": "2026-01-19T01:17:13Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-18T08:20:01Z", + "solarNoon": "2026-01-18T20:20:23Z", + "sunrise": "2026-01-18T15:22:41Z", + "sunriseCivil": "2026-01-18T14:54:12Z", + "sunriseNautical": "2026-01-18T14:22:08Z", + "sunriseAstronomical": "2026-01-18T13:50:45Z", + "sunset": "2026-01-19T01:18:16Z", + "sunsetCivil": "2026-01-19T01:46:43Z", + "sunsetNautical": "2026-01-19T02:18:47Z", + "sunsetAstronomical": "2026-01-19T02:50:09Z", + "temperatureMax": 18.18, + "temperatureMin": 9.08, + "windGustSpeedMax": 20.16, + "windSpeedAvg": 8.09, + "windSpeedMax": 10.05, + "daytimeForecast": { + "forecastStart": "2026-01-18T15:00:00Z", + "forecastEnd": "2026-01-19T03:00:00Z", + "cloudCover": 0.24, + "conditionCode": "MostlyClear", + "humidity": 0.63, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 18.18, + "temperatureMin": 9.19, + "windDirection": 29, + "windGustSpeedMax": 20.16, + "windSpeed": 8.65, + "windSpeedMax": 9.98 + }, + "overnightForecast": { + "forecastStart": "2026-01-19T03:00:00Z", + "forecastEnd": "2026-01-19T15:00:00Z", + "cloudCover": 0.16, + "conditionCode": "MostlyClear", + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 14.04, + "temperatureMin": 8.35, + "windDirection": 37, + "windGustSpeedMax": 13.01, + "windSpeed": 5.09, + "windSpeedMax": 6.54 + } + }, + { + "forecastStart": "2026-01-19T08:00:00Z", + "forecastEnd": "2026-01-20T08:00:00Z", + "conditionCode": "MostlyClear", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-19T16:11:15Z", + "moonset": "2026-01-20T02:22:55Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-19T08:20:20Z", + "solarNoon": "2026-01-19T20:20:41Z", + "sunrise": "2026-01-19T15:22:14Z", + "sunriseCivil": "2026-01-19T14:53:48Z", + "sunriseNautical": "2026-01-19T14:21:47Z", + "sunriseAstronomical": "2026-01-19T13:50:26Z", + "sunset": "2026-01-20T01:19:21Z", + "sunsetCivil": "2026-01-20T01:47:43Z", + "sunsetNautical": "2026-01-20T02:19:45Z", + "sunsetAstronomical": "2026-01-20T02:51:04Z", + "temperatureMax": 17.4, + "temperatureMin": 8.35, + "windGustSpeedMax": 17.91, + "windSpeedAvg": 7.28, + "windSpeedMax": 9.93, + "daytimeForecast": { + "forecastStart": "2026-01-19T15:00:00Z", + "forecastEnd": "2026-01-20T03:00:00Z", + "cloudCover": 0.15, + "conditionCode": "MostlyClear", + "humidity": 0.63, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 17.4, + "temperatureMin": 8.46, + "windDirection": 29, + "windGustSpeedMax": 17.91, + "windSpeed": 8.38, + "windSpeedMax": 9.93 + }, + "overnightForecast": { + "forecastStart": "2026-01-20T03:00:00Z", + "forecastEnd": "2026-01-20T15:00:00Z", + "cloudCover": 0.06, + "conditionCode": "Clear", + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 13.69, + "temperatureMin": 7.41, + "windDirection": 35, + "windGustSpeedMax": 16.49, + "windSpeed": 8.46, + "windSpeedMax": 9.54 + } + }, + { + "forecastStart": "2026-01-20T08:00:00Z", + "forecastEnd": "2026-01-21T08:00:00Z", + "conditionCode": "Clear", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-20T16:40:40Z", + "moonset": "2026-01-21T03:28:39Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-20T08:20:37Z", + "solarNoon": "2026-01-20T20:20:59Z", + "sunrise": "2026-01-20T15:21:45Z", + "sunriseCivil": "2026-01-20T14:53:23Z", + "sunriseNautical": "2026-01-20T14:21:24Z", + "sunriseAstronomical": "2026-01-20T13:50:06Z", + "sunset": "2026-01-21T01:20:26Z", + "sunsetCivil": "2026-01-21T01:48:44Z", + "sunsetNautical": "2026-01-21T02:20:44Z", + "sunsetAstronomical": "2026-01-21T02:52:00Z", + "temperatureMax": 17.26, + "temperatureMin": 7.41, + "windGustSpeedMax": 18.87, + "windSpeedAvg": 8.01, + "windSpeedMax": 9.54, + "daytimeForecast": { + "forecastStart": "2026-01-20T15:00:00Z", + "forecastEnd": "2026-01-21T03:00:00Z", + "cloudCover": 0.09, + "conditionCode": "Clear", + "humidity": 0.65, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 17.26, + "temperatureMin": 7.95, + "windDirection": 35, + "windGustSpeedMax": 18.87, + "windSpeed": 8.24, + "windSpeedMax": 9.48 + }, + "overnightForecast": { + "forecastStart": "2026-01-21T03:00:00Z", + "forecastEnd": "2026-01-21T15:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 13.82, + "temperatureMin": 6.86, + "windDirection": 37, + "windGustSpeedMax": 13.61, + "windSpeed": 6.29, + "windSpeedMax": 7.08 + } + }, + { + "forecastStart": "2026-01-21T08:00:00Z", + "forecastEnd": "2026-01-22T08:00:00Z", + "conditionCode": "MostlyClear", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-21T17:06:43Z", + "moonset": "2026-01-22T04:34:00Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-21T08:20:54Z", + "solarNoon": "2026-01-21T20:21:16Z", + "sunrise": "2026-01-21T15:21:14Z", + "sunriseCivil": "2026-01-21T14:52:56Z", + "sunriseNautical": "2026-01-21T14:21:00Z", + "sunriseAstronomical": "2026-01-21T13:49:44Z", + "sunset": "2026-01-22T01:21:31Z", + "sunsetCivil": "2026-01-22T01:49:45Z", + "sunsetNautical": "2026-01-22T02:21:42Z", + "sunsetAstronomical": "2026-01-22T02:52:56Z", + "temperatureMax": 16.24, + "temperatureMin": 6.86, + "windGustSpeedMax": 16.74, + "windSpeedAvg": 5.86, + "windSpeedMax": 7.11, + "daytimeForecast": { + "forecastStart": "2026-01-21T15:00:00Z", + "forecastEnd": "2026-01-22T03:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "humidity": 0.69, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 16.24, + "temperatureMin": 6.96, + "windDirection": 20, + "windGustSpeedMax": 16.74, + "windSpeed": 6.51, + "windSpeedMax": 7.11 + }, + "overnightForecast": { + "forecastStart": "2026-01-22T03:00:00Z", + "forecastEnd": "2026-01-22T15:00:00Z", + "cloudCover": 0.46, + "conditionCode": "PartlyCloudy", + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 12.83, + "temperatureMin": 8.1, + "windDirection": 46, + "windGustSpeedMax": 11.04, + "windSpeed": 4.22, + "windSpeedMax": 4.9 + } + }, + { + "forecastStart": "2026-01-22T08:00:00Z", + "forecastEnd": "2026-01-23T08:00:00Z", + "conditionCode": "PartlyCloudy", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-22T17:31:08Z", + "moonset": "2026-01-23T05:39:27Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-22T08:21:11Z", + "solarNoon": "2026-01-22T20:21:32Z", + "sunrise": "2026-01-22T15:20:40Z", + "sunriseCivil": "2026-01-22T14:52:26Z", + "sunriseNautical": "2026-01-22T14:20:34Z", + "sunriseAstronomical": "2026-01-22T13:49:21Z", + "sunset": "2026-01-23T01:22:37Z", + "sunsetCivil": "2026-01-23T01:50:47Z", + "sunsetNautical": "2026-01-23T02:22:41Z", + "sunsetAstronomical": "2026-01-23T02:53:52Z", + "temperatureMax": 13.4, + "temperatureMin": 8.1, + "windGustSpeedMax": 19.16, + "windSpeedAvg": 5.72, + "windSpeedMax": 8.56, + "daytimeForecast": { + "forecastStart": "2026-01-22T15:00:00Z", + "forecastEnd": "2026-01-23T03:00:00Z", + "cloudCover": 0.62, + "conditionCode": "PartlyCloudy", + "humidity": 0.77, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 13.4, + "temperatureMin": 8.26, + "windDirection": 329, + "windGustSpeedMax": 19.16, + "windSpeed": 6.09, + "windSpeedMax": 8.56 + }, + "overnightForecast": { + "forecastStart": "2026-01-23T03:00:00Z", + "forecastEnd": "2026-01-23T15:00:00Z", + "cloudCover": 0.71, + "conditionCode": "MostlyCloudy", + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 11.65, + "temperatureMin": 8.49, + "windDirection": 305, + "windGustSpeedMax": 17.51, + "windSpeed": 6.27, + "windSpeedMax": 7.17 + } + }, + { + "forecastStart": "2026-01-23T08:00:00Z", + "forecastEnd": "2026-01-24T08:00:00Z", + "conditionCode": "PartlyCloudy", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-23T17:55:04Z", + "moonset": "2026-01-24T06:45:58Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-23T08:21:26Z", + "solarNoon": "2026-01-23T20:21:48Z", + "sunrise": "2026-01-23T15:20:05Z", + "sunriseCivil": "2026-01-23T14:51:55Z", + "sunriseNautical": "2026-01-23T14:20:06Z", + "sunriseAstronomical": "2026-01-23T13:48:55Z", + "sunset": "2026-01-24T01:23:43Z", + "sunsetCivil": "2026-01-24T01:51:49Z", + "sunsetNautical": "2026-01-24T02:23:41Z", + "sunsetAstronomical": "2026-01-24T02:54:49Z", + "temperatureMax": 13.01, + "temperatureMin": 8.49, + "windGustSpeedMax": 13.85, + "windSpeedAvg": 6.88, + "windSpeedMax": 10.62, + "daytimeForecast": { + "forecastStart": "2026-01-23T15:00:00Z", + "forecastEnd": "2026-01-24T03:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 13.01, + "temperatureMin": 8.74, + "windDirection": 303, + "windGustSpeedMax": 13.85, + "windSpeed": 5.96, + "windSpeedMax": 9.31 + }, + "overnightForecast": { + "forecastStart": "2026-01-24T03:00:00Z", + "forecastEnd": "2026-01-24T15:00:00Z", + "cloudCover": 0.24, + "conditionCode": "MostlyClear", + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 11.59, + "temperatureMin": 8.31, + "windDirection": 263, + "windGustSpeedMax": 14.96, + "windSpeed": 9.88, + "windSpeedMax": 10.77 + } + }, + { + "forecastStart": "2026-01-24T08:00:00Z", + "forecastEnd": "2026-01-25T08:00:00Z", + "conditionCode": "MostlyClear", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-24T18:20:13Z", + "moonset": "2026-01-25T07:54:38Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-24T08:21:41Z", + "solarNoon": "2026-01-24T20:22:02Z", + "sunrise": "2026-01-24T15:19:29Z", + "sunriseCivil": "2026-01-24T14:51:22Z", + "sunriseNautical": "2026-01-24T14:19:36Z", + "sunriseAstronomical": "2026-01-24T13:48:28Z", + "sunset": "2026-01-25T01:24:50Z", + "sunsetCivil": "2026-01-25T01:52:51Z", + "sunsetNautical": "2026-01-25T02:24:40Z", + "sunsetAstronomical": "2026-01-25T02:55:45Z", + "temperatureMax": 12.51, + "temperatureMin": 8.31, + "windGustSpeedMax": 21.4, + "windSpeedAvg": 9.99, + "windSpeedMax": 13.53, + "daytimeForecast": { + "forecastStart": "2026-01-24T15:00:00Z", + "forecastEnd": "2026-01-25T03:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "humidity": 0.75, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 12.51, + "temperatureMin": 8.31, + "windDirection": 318, + "windGustSpeedMax": 21.4, + "windSpeed": 11.5, + "windSpeedMax": 13.53 + }, + "overnightForecast": { + "forecastStart": "2026-01-25T03:00:00Z", + "forecastEnd": "2026-01-25T15:00:00Z", + "cloudCover": 0.41, + "conditionCode": "PartlyCloudy", + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 10.99, + "temperatureMin": 8.32, + "windDirection": 170, + "windGustSpeedMax": 16.36, + "windSpeed": 7.05, + "windSpeedMax": 8.54 + } + }, + { + "forecastStart": "2026-01-25T08:00:00Z", + "forecastEnd": "2026-01-26T08:00:00Z", + "conditionCode": "PartlyCloudy", + "maxUvIndex": 3, + "moonPhase": "waxingCrescent", + "moonrise": "2026-01-25T18:48:10Z", + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "solarMidnight": "2026-01-25T08:21:55Z", + "solarNoon": "2026-01-25T20:22:16Z", + "sunrise": "2026-01-25T15:18:50Z", + "sunriseCivil": "2026-01-25T14:50:48Z", + "sunriseNautical": "2026-01-25T14:19:04Z", + "sunriseAstronomical": "2026-01-25T13:47:59Z", + "sunset": "2026-01-26T01:25:56Z", + "sunsetCivil": "2026-01-26T01:53:53Z", + "sunsetNautical": "2026-01-26T02:25:40Z", + "sunsetAstronomical": "2026-01-26T02:56:42Z", + "temperatureMax": 13.9, + "temperatureMin": 8.32, + "windGustSpeedMax": 15.97, + "windSpeedAvg": 9.09, + "windSpeedMax": 11.17, + "daytimeForecast": { + "forecastStart": "2026-01-25T15:00:00Z", + "forecastEnd": "2026-01-26T03:00:00Z", + "cloudCover": 0.51, + "conditionCode": "PartlyCloudy", + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 13.9, + "temperatureMin": 8.74, + "windDirection": 45, + "windGustSpeedMax": 15.97, + "windSpeed": 10.2, + "windSpeedMax": 11.17 + }, + "overnightForecast": { + "forecastStart": "2026-01-26T03:00:00Z", + "forecastEnd": "2026-01-26T15:00:00Z", + "cloudCover": 0.56, + "conditionCode": "PartlyCloudy", + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "snowfallAmount": 0, + "temperatureMax": 12.43, + "temperatureMin": 9.06, + "windDirection": 57, + "windGustSpeedMax": 11.61, + "windSpeed": 7.45, + "windSpeedMax": 9.93 + } + } + ] + }, + "forecastHourly": { + "name": "HourlyForecast", + "metadata": { + "attributionURL": "https://developer.apple.com/weatherkit/data-source-attribution/", + "expireTime": "2026-01-17T01:37:11Z", + "latitude": 37.77, + "longitude": -122.42, + "readTime": "2026-01-17T00:37:11Z", + "reportedTime": "2026-01-16T23:05:34Z", + "units": "m", + "version": 1, + "sourceType": "modeled" + }, + "hours": [ + { + "forecastStart": "2026-01-16T06:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.91, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.96, + "temperatureApparent": 11.68, + "temperatureDewPoint": 8.24, + "uvIndex": 0, + "visibility": 25281, + "windDirection": 5, + "windGust": 2.65, + "windSpeed": 0.73 + }, + { + "forecastStart": "2026-01-16T07:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.43, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.37, + "temperatureApparent": 11.14, + "temperatureDewPoint": 7.86, + "uvIndex": 0, + "visibility": 24048, + "windDirection": 182, + "windGust": 2.79, + "windSpeed": 0.8 + }, + { + "forecastStart": "2026-01-16T08:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.53, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.62, + "temperatureApparent": 10.52, + "temperatureDewPoint": 7.85, + "uvIndex": 0, + "visibility": 22707, + "windDirection": 357, + "windGust": 3.88, + "windSpeed": 0.82 + }, + { + "forecastStart": "2026-01-16T09:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.5, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.39, + "temperatureApparent": 10.33, + "temperatureDewPoint": 7.63, + "uvIndex": 0, + "visibility": 25066, + "windDirection": 200, + "windGust": 2.5, + "windSpeed": 0.68 + }, + { + "forecastStart": "2026-01-16T10:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.89, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.59, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.56, + "temperatureApparent": 9.41, + "temperatureDewPoint": 7.84, + "uvIndex": 0, + "visibility": 18724, + "windDirection": 9, + "windGust": 4.97, + "windSpeed": 2.56 + }, + { + "forecastStart": "2026-01-16T11:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.9, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.67, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.89, + "temperatureApparent": 8.97, + "temperatureDewPoint": 7.34, + "uvIndex": 0, + "visibility": 16412, + "windDirection": 338, + "windGust": 4.78, + "windSpeed": 1.75 + }, + { + "forecastStart": "2026-01-16T12:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.91, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.42, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.94, + "temperatureApparent": 8.37, + "temperatureDewPoint": 7.55, + "uvIndex": 0, + "visibility": 16605, + "windDirection": 354, + "windGust": 7.59, + "windSpeed": 4.32 + }, + { + "forecastStart": "2026-01-16T13:00:00Z", + "cloudCover": 0.04, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.3, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.08, + "temperatureApparent": 8.67, + "temperatureDewPoint": 7.2, + "uvIndex": 0, + "visibility": 19567, + "windDirection": 336, + "windGust": 6.45, + "windSpeed": 3.24 + }, + { + "forecastStart": "2026-01-16T14:00:00Z", + "cloudCover": 0.06, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.79, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.24, + "temperatureApparent": 9.08, + "temperatureDewPoint": 6.68, + "uvIndex": 0, + "visibility": 20343, + "windDirection": 339, + "windGust": 5.93, + "windSpeed": 2.13 + }, + { + "forecastStart": "2026-01-16T15:00:00Z", + "cloudCover": 0.3, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.1, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.02, + "temperatureApparent": 9.47, + "temperatureDewPoint": 6.97, + "uvIndex": 0, + "visibility": 15151, + "windDirection": 279, + "windGust": 3.14, + "windSpeed": 0.99 + }, + { + "forecastStart": "2026-01-16T16:00:00Z", + "cloudCover": 0.03, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.19, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.71, + "temperatureApparent": 11.3, + "temperatureDewPoint": 7.14, + "uvIndex": 0, + "visibility": 19853, + "windDirection": 339, + "windGust": 5.91, + "windSpeed": 3.46 + }, + { + "forecastStart": "2026-01-16T17:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.69, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.86, + "temperatureApparent": 15.63, + "temperatureDewPoint": 8.89, + "uvIndex": 1, + "visibility": 21686, + "windDirection": 245, + "windGust": 4.28, + "windSpeed": 1.65 + }, + { + "forecastStart": "2026-01-16T18:00:00Z", + "cloudCover": 0.01, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.12, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.33, + "temperatureApparent": 18.29, + "temperatureDewPoint": 9.35, + "uvIndex": 1, + "visibility": 25615, + "windDirection": 44, + "windGust": 5.63, + "windSpeed": 1.31 + }, + { + "forecastStart": "2026-01-16T19:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.59, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.16, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.21, + "temperatureApparent": 19.27, + "temperatureDewPoint": 8.19, + "uvIndex": 2, + "visibility": 34519, + "windDirection": 69, + "windGust": 9.4, + "windSpeed": 4.72 + }, + { + "forecastStart": "2026-01-16T20:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.53, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.71, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.61, + "temperatureApparent": 20.71, + "temperatureDewPoint": 7.92, + "uvIndex": 3, + "visibility": 35618, + "windDirection": 81, + "windGust": 8.53, + "windSpeed": 4.12 + }, + { + "forecastStart": "2026-01-16T21:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.44, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.86, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 19.46, + "temperatureApparent": 22.52, + "temperatureDewPoint": 6.89, + "uvIndex": 3, + "visibility": 38272, + "windDirection": 75, + "windGust": 5.78, + "windSpeed": 3.32 + }, + { + "forecastStart": "2026-01-16T22:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.4, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.42, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 19.87, + "temperatureApparent": 22.74, + "temperatureDewPoint": 5.87, + "uvIndex": 2, + "visibility": 40905, + "windDirection": 59, + "windGust": 8.74, + "windSpeed": 3.64 + }, + { + "forecastStart": "2026-01-16T23:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.45, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.42, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 19.25, + "temperatureApparent": 21.53, + "temperatureDewPoint": 7.02, + "uvIndex": 1, + "visibility": 35011, + "windDirection": 3, + "windGust": 9.57, + "windSpeed": 6.19 + }, + { + "forecastStart": "2026-01-17T00:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.58, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.63, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.2, + "temperatureApparent": 17.49, + "temperatureDewPoint": 8.86, + "uvIndex": 0, + "visibility": 32714, + "windDirection": 2, + "windGust": 18.66, + "windSpeed": 11.53 + }, + { + "forecastStart": "2026-01-17T01:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.65, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.8, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.13, + "temperatureApparent": 12.79, + "temperatureDewPoint": 8.6, + "uvIndex": 0, + "visibility": 29392, + "windDirection": 347, + "windGust": 17.07, + "windSpeed": 10.92 + }, + { + "forecastStart": "2026-01-17T02:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.68, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.62, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.69, + "temperatureApparent": 10.87, + "temperatureDewPoint": 7.89, + "uvIndex": 0, + "visibility": 28074, + "windDirection": 341, + "windGust": 16.19, + "windSpeed": 10.59 + }, + { + "forecastStart": "2026-01-17T03:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.75, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.15, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.51, + "temperatureApparent": 9.61, + "temperatureDewPoint": 8.2, + "uvIndex": 0, + "visibility": 25398, + "windDirection": 342, + "windGust": 16.85, + "windSpeed": 10.57 + }, + { + "forecastStart": "2026-01-17T04:00:00Z", + "cloudCover": 0.01, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.61, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.77, + "temperatureApparent": 8.75, + "temperatureDewPoint": 8.06, + "uvIndex": 0, + "visibility": 23936, + "windDirection": 347, + "windGust": 18.52, + "windSpeed": 10.89 + }, + { + "forecastStart": "2026-01-17T05:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.12, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.94, + "temperatureApparent": 8.22, + "temperatureDewPoint": 7.99, + "uvIndex": 0, + "visibility": 23576, + "windDirection": 344, + "windGust": 16.32, + "windSpeed": 9.92 + }, + { + "forecastStart": "2026-01-17T06:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.26, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.38, + "temperatureApparent": 7.61, + "temperatureDewPoint": 7.79, + "uvIndex": 0, + "visibility": 22835, + "windDirection": 348, + "windGust": 16.17, + "windSpeed": 10.07 + }, + { + "forecastStart": "2026-01-17T07:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.23, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.85, + "temperatureApparent": 7.02, + "temperatureDewPoint": 7.62, + "uvIndex": 0, + "visibility": 21793, + "windDirection": 351, + "windGust": 15.88, + "windSpeed": 10.2 + }, + { + "forecastStart": "2026-01-17T08:00:00Z", + "cloudCover": 0.04, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.15, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.95, + "temperatureApparent": 7.52, + "temperatureDewPoint": 7.02, + "uvIndex": 0, + "visibility": 22640, + "windDirection": 17, + "windGust": 13.96, + "windSpeed": 9.07 + }, + { + "forecastStart": "2026-01-17T09:00:00Z", + "cloudCover": 0.05, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.24, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.4, + "temperatureApparent": 6.98, + "temperatureDewPoint": 7.01, + "uvIndex": 0, + "visibility": 21858, + "windDirection": 23, + "windGust": 14.17, + "windSpeed": 9.08 + }, + { + "forecastStart": "2026-01-17T10:00:00Z", + "cloudCover": 0.07, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.57, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.01, + "temperatureApparent": 6.5, + "temperatureDewPoint": 6.79, + "uvIndex": 0, + "visibility": 21783, + "windDirection": 27, + "windGust": 14.07, + "windSpeed": 9.38 + }, + { + "forecastStart": "2026-01-17T11:00:00Z", + "cloudCover": 0.14, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.66, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.72, + "temperatureApparent": 6.08, + "temperatureDewPoint": 6.51, + "uvIndex": 0, + "visibility": 21016, + "windDirection": 26, + "windGust": 14.98, + "windSpeed": 9.95 + }, + { + "forecastStart": "2026-01-17T12:00:00Z", + "cloudCover": 0.24, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.7, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.54, + "temperatureApparent": 5.59, + "temperatureDewPoint": 6.5, + "uvIndex": 0, + "visibility": 20080, + "windDirection": 24, + "windGust": 16.9, + "windSpeed": 11.06 + }, + { + "forecastStart": "2026-01-17T13:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.91, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.31, + "temperatureApparent": 5.4, + "temperatureDewPoint": 6.27, + "uvIndex": 0, + "visibility": 19963, + "windDirection": 26, + "windGust": 16.98, + "windSpeed": 11.28 + }, + { + "forecastStart": "2026-01-17T14:00:00Z", + "cloudCover": 0.42, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.34, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.14, + "temperatureApparent": 5.4, + "temperatureDewPoint": 6.11, + "uvIndex": 0, + "visibility": 20565, + "windDirection": 27, + "windGust": 16.86, + "windSpeed": 11.08 + }, + { + "forecastStart": "2026-01-17T15:00:00Z", + "cloudCover": 0.56, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.65, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.04, + "temperatureApparent": 5.55, + "temperatureDewPoint": 6.01, + "uvIndex": 0, + "visibility": 21167, + "windDirection": 30, + "windGust": 16.38, + "windSpeed": 10.9 + }, + { + "forecastStart": "2026-01-17T16:00:00Z", + "cloudCover": 0.57, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.03, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.36, + "temperatureApparent": 6.37, + "temperatureDewPoint": 6.15, + "uvIndex": 0, + "visibility": 18945, + "windDirection": 35, + "windGust": 16.9, + "windSpeed": 11.12 + }, + { + "forecastStart": "2026-01-17T17:00:00Z", + "cloudCover": 0.58, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.58, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.44, + "temperatureApparent": 7.94, + "temperatureDewPoint": 6.7, + "uvIndex": 1, + "visibility": 19316, + "windDirection": 36, + "windGust": 16.93, + "windSpeed": 11.17 + }, + { + "forecastStart": "2026-01-17T18:00:00Z", + "cloudCover": 0.77, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.84, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.98, + "temperatureApparent": 8.8, + "temperatureDewPoint": 7.29, + "uvIndex": 1, + "visibility": 21518, + "windDirection": 38, + "windGust": 16.37, + "windSpeed": 11.3 + }, + { + "forecastStart": "2026-01-17T19:00:00Z", + "cloudCover": 0.78, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.83, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.44, + "temperatureApparent": 10.28, + "temperatureDewPoint": 7.73, + "uvIndex": 2, + "visibility": 23392, + "windDirection": 36, + "windGust": 16.75, + "windSpeed": 11.28 + }, + { + "forecastStart": "2026-01-17T20:00:00Z", + "cloudCover": 0.77, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.67, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.36, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.1, + "temperatureApparent": 12.23, + "temperatureDewPoint": 8.06, + "uvIndex": 2, + "visibility": 26378, + "windDirection": 32, + "windGust": 17.3, + "windSpeed": 11.03 + }, + { + "forecastStart": "2026-01-17T21:00:00Z", + "cloudCover": 0.73, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.62, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.86, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.48, + "temperatureApparent": 13.83, + "temperatureDewPoint": 8.23, + "uvIndex": 2, + "visibility": 27132, + "windDirection": 27, + "windGust": 18.8, + "windSpeed": 11.17 + }, + { + "forecastStart": "2026-01-17T22:00:00Z", + "cloudCover": 0.78, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.58, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.48, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.42, + "temperatureApparent": 14.69, + "temperatureDewPoint": 8.13, + "uvIndex": 2, + "visibility": 28404, + "windDirection": 26, + "windGust": 20.39, + "windSpeed": 11.13 + }, + { + "forecastStart": "2026-01-17T23:00:00Z", + "cloudCover": 0.76, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.56, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.39, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.88, + "temperatureApparent": 15.38, + "temperatureDewPoint": 8.05, + "uvIndex": 1, + "visibility": 28630, + "windDirection": 24, + "windGust": 20.01, + "windSpeed": 10.68 + }, + { + "forecastStart": "2026-01-18T00:00:00Z", + "cloudCover": 0.68, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.57, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.42, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.78, + "temperatureApparent": 15.67, + "temperatureDewPoint": 8.21, + "uvIndex": 0, + "visibility": 28195, + "windDirection": 21, + "windGust": 18.22, + "windSpeed": 9.93 + }, + { + "forecastStart": "2026-01-18T01:00:00Z", + "cloudCover": 0.79, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.61, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.7, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.47, + "temperatureApparent": 14.06, + "temperatureDewPoint": 7.98, + "uvIndex": 0, + "visibility": 27557, + "windDirection": 20, + "windGust": 17.83, + "windSpeed": 9.49 + }, + { + "forecastStart": "2026-01-18T02:00:00Z", + "cloudCover": 0.74, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.65, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.12, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.36, + "temperatureApparent": 12.8, + "temperatureDewPoint": 7.87, + "uvIndex": 0, + "visibility": 27266, + "windDirection": 20, + "windGust": 16.92, + "windSpeed": 9.45 + }, + { + "forecastStart": "2026-01-18T03:00:00Z", + "cloudCover": 0.69, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.68, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.5, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.41, + "temperatureApparent": 11.91, + "temperatureDewPoint": 7.62, + "uvIndex": 0, + "visibility": 27301, + "windDirection": 21, + "windGust": 14.77, + "windSpeed": 8.85 + }, + { + "forecastStart": "2026-01-18T04:00:00Z", + "cloudCover": 0.85, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.76, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.58, + "temperatureApparent": 11.22, + "temperatureDewPoint": 7.46, + "uvIndex": 0, + "visibility": 27156, + "windDirection": 26, + "windGust": 14.62, + "windSpeed": 8.91 + }, + { + "forecastStart": "2026-01-18T05:00:00Z", + "cloudCover": 0.87, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.95, + "temperatureApparent": 10.78, + "temperatureDewPoint": 7.26, + "uvIndex": 0, + "visibility": 26528, + "windDirection": 26, + "windGust": 13.29, + "windSpeed": 8.33 + }, + { + "forecastStart": "2026-01-18T06:00:00Z", + "cloudCover": 0.89, + "conditionCode": "Cloudy", + "daylight": false, + "humidity": 0.75, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.25, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.47, + "temperatureApparent": 10.34, + "temperatureDewPoint": 7.19, + "uvIndex": 0, + "visibility": 26125, + "windDirection": 29, + "windGust": 13.6, + "windSpeed": 8.33 + }, + { + "forecastStart": "2026-01-18T07:00:00Z", + "cloudCover": 0.87, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.4, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.01, + "temperatureApparent": 10.01, + "temperatureDewPoint": 6.94, + "uvIndex": 0, + "visibility": 24304, + "windDirection": 30, + "windGust": 13.12, + "windSpeed": 7.95 + }, + { + "forecastStart": "2026-01-18T08:00:00Z", + "cloudCover": 0.83, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.42, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.59, + "temperatureApparent": 9.4, + "temperatureDewPoint": 6.91, + "uvIndex": 0, + "visibility": 22807, + "windDirection": 32, + "windGust": 14.07, + "windSpeed": 8.35 + }, + { + "forecastStart": "2026-01-18T09:00:00Z", + "cloudCover": 0.78, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.42, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.22, + "temperatureApparent": 8.89, + "temperatureDewPoint": 6.74, + "uvIndex": 0, + "visibility": 22647, + "windDirection": 32, + "windGust": 14.04, + "windSpeed": 8.59 + }, + { + "forecastStart": "2026-01-18T10:00:00Z", + "cloudCover": 0.82, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.55, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.85, + "temperatureApparent": 8.61, + "temperatureDewPoint": 6.56, + "uvIndex": 0, + "visibility": 22592, + "windDirection": 33, + "windGust": 13.99, + "windSpeed": 8.49 + }, + { + "forecastStart": "2026-01-18T11:00:00Z", + "cloudCover": 0.86, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.34, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.54, + "temperatureApparent": 8.16, + "temperatureDewPoint": 6.62, + "uvIndex": 0, + "visibility": 23167, + "windDirection": 29, + "windGust": 13.28, + "windSpeed": 9.03 + }, + { + "forecastStart": "2026-01-18T12:00:00Z", + "cloudCover": 0.86, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.05, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.33, + "temperatureApparent": 7.71, + "temperatureDewPoint": 6.59, + "uvIndex": 0, + "visibility": 22506, + "windDirection": 33, + "windGust": 14.22, + "windSpeed": 9.66 + }, + { + "forecastStart": "2026-01-18T13:00:00Z", + "cloudCover": 0.84, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.98, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.21, + "temperatureApparent": 7.5, + "temperatureDewPoint": 6.65, + "uvIndex": 0, + "visibility": 22218, + "windDirection": 35, + "windGust": 13.78, + "windSpeed": 9.83 + }, + { + "forecastStart": "2026-01-18T14:00:00Z", + "cloudCover": 0.85, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.17, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.08, + "temperatureApparent": 7.3, + "temperatureDewPoint": 6.52, + "uvIndex": 0, + "visibility": 21996, + "windDirection": 35, + "windGust": 14.57, + "windSpeed": 10.05 + }, + { + "forecastStart": "2026-01-18T15:00:00Z", + "cloudCover": 0.78, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.39, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.19, + "temperatureApparent": 7.34, + "temperatureDewPoint": 6.63, + "uvIndex": 0, + "visibility": 22507, + "windDirection": 35, + "windGust": 14.86, + "windSpeed": 9.98 + }, + { + "forecastStart": "2026-01-18T16:00:00Z", + "cloudCover": 0.6, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.49, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.58, + "temperatureApparent": 8.1, + "temperatureDewPoint": 6.66, + "uvIndex": 0, + "visibility": 23001, + "windDirection": 38, + "windGust": 14.49, + "windSpeed": 9.73 + }, + { + "forecastStart": "2026-01-18T17:00:00Z", + "cloudCover": 0.55, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.72, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.57, + "temperatureApparent": 9.93, + "temperatureDewPoint": 7.08, + "uvIndex": 1, + "visibility": 25449, + "windDirection": 42, + "windGust": 15.2, + "windSpeed": 9.09 + }, + { + "forecastStart": "2026-01-18T18:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.81, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.15, + "temperatureApparent": 12.33, + "temperatureDewPoint": 7.45, + "uvIndex": 1, + "visibility": 26640, + "windDirection": 42, + "windGust": 15.01, + "windSpeed": 9.21 + }, + { + "forecastStart": "2026-01-18T19:00:00Z", + "cloudCover": 0.26, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.66, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.57, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.9, + "temperatureApparent": 14.42, + "temperatureDewPoint": 7.65, + "uvIndex": 2, + "visibility": 27682, + "windDirection": 48, + "windGust": 15.8, + "windSpeed": 9.11 + }, + { + "forecastStart": "2026-01-18T20:00:00Z", + "cloudCover": 0.17, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.59, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.81, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.65, + "temperatureApparent": 16.41, + "temperatureDewPoint": 7.66, + "uvIndex": 3, + "visibility": 28854, + "windDirection": 41, + "windGust": 17.27, + "windSpeed": 9.53 + }, + { + "forecastStart": "2026-01-18T21:00:00Z", + "cloudCover": 0.1, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.54, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.03, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.97, + "temperatureApparent": 18.03, + "temperatureDewPoint": 7.6, + "uvIndex": 3, + "visibility": 29576, + "windDirection": 32, + "windGust": 19.32, + "windSpeed": 9.45 + }, + { + "forecastStart": "2026-01-18T22:00:00Z", + "cloudCover": 0.18, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.51, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.52, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.8, + "temperatureApparent": 18.7, + "temperatureDewPoint": 7.53, + "uvIndex": 2, + "visibility": 29821, + "windDirection": 27, + "windGust": 20.16, + "windSpeed": 9.03 + }, + { + "forecastStart": "2026-01-18T23:00:00Z", + "cloudCover": 0.05, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.5, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.22, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 18.18, + "temperatureApparent": 19.54, + "temperatureDewPoint": 7.59, + "uvIndex": 1, + "visibility": 29869, + "windDirection": 21, + "windGust": 19.28, + "windSpeed": 8.49 + }, + { + "forecastStart": "2026-01-19T00:00:00Z", + "cloudCover": 0.1, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.5, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.01, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.86, + "temperatureApparent": 18.68, + "temperatureDewPoint": 7.29, + "uvIndex": 0, + "visibility": 29687, + "windDirection": 9, + "windGust": 18.48, + "windSpeed": 7.99 + }, + { + "forecastStart": "2026-01-19T01:00:00Z", + "cloudCover": 0.09, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.53, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.94, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.67, + "temperatureApparent": 15.43, + "temperatureDewPoint": 7.04, + "uvIndex": 0, + "visibility": 29314, + "windDirection": 0, + "windGust": 17.16, + "windSpeed": 7.43 + }, + { + "forecastStart": "2026-01-19T02:00:00Z", + "cloudCover": 0.03, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.59, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.24, + "temperatureApparent": 13.58, + "temperatureDewPoint": 7.28, + "uvIndex": 0, + "visibility": 28859, + "windDirection": 0, + "windGust": 15.11, + "windSpeed": 6.78 + }, + { + "forecastStart": "2026-01-19T03:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.64, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.04, + "temperatureApparent": 12.55, + "temperatureDewPoint": 7.33, + "uvIndex": 0, + "visibility": 28557, + "windDirection": 3, + "windGust": 13.01, + "windSpeed": 6.04 + }, + { + "forecastStart": "2026-01-19T04:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.68, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.96, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.14, + "temperatureApparent": 11.76, + "temperatureDewPoint": 7.36, + "uvIndex": 0, + "visibility": 27881, + "windDirection": 11, + "windGust": 11.88, + "windSpeed": 5.61 + }, + { + "forecastStart": "2026-01-19T05:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.97, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.36, + "temperatureApparent": 11.06, + "temperatureDewPoint": 7.45, + "uvIndex": 0, + "visibility": 27407, + "windDirection": 17, + "windGust": 11.11, + "windSpeed": 5.26 + }, + { + "forecastStart": "2026-01-19T06:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.01, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.67, + "temperatureApparent": 10.49, + "temperatureDewPoint": 7.19, + "uvIndex": 0, + "visibility": 27084, + "windDirection": 26, + "windGust": 10.39, + "windSpeed": 4.96 + }, + { + "forecastStart": "2026-01-19T07:00:00Z", + "cloudCover": 0.08, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.77, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.01, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.89, + "temperatureApparent": 9.97, + "temperatureDewPoint": 7.02, + "uvIndex": 0, + "visibility": 26394, + "windDirection": 33, + "windGust": 9.21, + "windSpeed": 4.52 + }, + { + "forecastStart": "2026-01-19T08:00:00Z", + "cloudCover": 0.17, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.89, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.28, + "temperatureApparent": 9.64, + "temperatureDewPoint": 6.98, + "uvIndex": 0, + "visibility": 25832, + "windDirection": 42, + "windGust": 8.07, + "windSpeed": 4.15 + }, + { + "forecastStart": "2026-01-19T09:00:00Z", + "cloudCover": 0.26, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.76, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.76, + "temperatureApparent": 9.26, + "temperatureDewPoint": 6.83, + "uvIndex": 0, + "visibility": 24877, + "windDirection": 51, + "windGust": 7.75, + "windSpeed": 4.24 + }, + { + "forecastStart": "2026-01-19T10:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.66, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.32, + "temperatureApparent": 8.75, + "temperatureDewPoint": 6.58, + "uvIndex": 0, + "visibility": 22331, + "windDirection": 56, + "windGust": 7.8, + "windSpeed": 4.59 + }, + { + "forecastStart": "2026-01-19T11:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.43, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.97, + "temperatureApparent": 8.31, + "temperatureDewPoint": 6.41, + "uvIndex": 0, + "visibility": 21652, + "windDirection": 54, + "windGust": 7.97, + "windSpeed": 4.91 + }, + { + "forecastStart": "2026-01-19T12:00:00Z", + "cloudCover": 0.29, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.13, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.83, + "temperatureApparent": 8.15, + "temperatureDewPoint": 6.62, + "uvIndex": 0, + "visibility": 20961, + "windDirection": 51, + "windGust": 7.97, + "windSpeed": 5.11 + }, + { + "forecastStart": "2026-01-19T13:00:00Z", + "cloudCover": 0.23, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.03, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.41, + "temperatureApparent": 7.53, + "temperatureDewPoint": 6.2, + "uvIndex": 0, + "visibility": 20134, + "windDirection": 47, + "windGust": 8.5, + "windSpeed": 5.49 + }, + { + "forecastStart": "2026-01-19T14:00:00Z", + "cloudCover": 0.19, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.08, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.36, + "temperatureApparent": 7.26, + "temperatureDewPoint": 6.32, + "uvIndex": 0, + "visibility": 19096, + "windDirection": 44, + "windGust": 9.02, + "windSpeed": 5.97 + }, + { + "forecastStart": "2026-01-19T15:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.23, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.46, + "temperatureApparent": 7.25, + "temperatureDewPoint": 6.25, + "uvIndex": 0, + "visibility": 17581, + "windDirection": 42, + "windGust": 9.44, + "windSpeed": 6.54 + }, + { + "forecastStart": "2026-01-19T16:00:00Z", + "cloudCover": 0.3, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.46, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.68, + "temperatureApparent": 8.44, + "temperatureDewPoint": 6.13, + "uvIndex": 0, + "visibility": 18744, + "windDirection": 42, + "windGust": 10.29, + "windSpeed": 7.37 + }, + { + "forecastStart": "2026-01-19T17:00:00Z", + "cloudCover": 0.31, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.81, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.85, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.55, + "temperatureApparent": 10.22, + "temperatureDewPoint": 6.45, + "uvIndex": 1, + "visibility": 19891, + "windDirection": 44, + "windGust": 10.95, + "windSpeed": 7.71 + }, + { + "forecastStart": "2026-01-19T18:00:00Z", + "cloudCover": 0.32, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.16, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.87, + "temperatureApparent": 11.62, + "temperatureDewPoint": 6.81, + "uvIndex": 1, + "visibility": 24708, + "windDirection": 42, + "windGust": 11.26, + "windSpeed": 7.8 + }, + { + "forecastStart": "2026-01-19T19:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.68, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.06, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.68, + "temperatureApparent": 13.27, + "temperatureDewPoint": 6.93, + "uvIndex": 2, + "visibility": 27216, + "windDirection": 39, + "windGust": 12.84, + "windSpeed": 8.6 + }, + { + "forecastStart": "2026-01-19T20:00:00Z", + "cloudCover": 0.11, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.6, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.38, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.58, + "temperatureApparent": 15.49, + "temperatureDewPoint": 6.9, + "uvIndex": 3, + "visibility": 28895, + "windDirection": 33, + "windGust": 15.22, + "windSpeed": 9.46 + }, + { + "forecastStart": "2026-01-19T21:00:00Z", + "cloudCover": 0.06, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.54, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.63, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.06, + "temperatureApparent": 17.02, + "temperatureDewPoint": 6.75, + "uvIndex": 3, + "visibility": 30281, + "windDirection": 27, + "windGust": 16.44, + "windSpeed": 9.92 + }, + { + "forecastStart": "2026-01-19T22:00:00Z", + "cloudCover": 0.1, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.51, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.1, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.97, + "temperatureApparent": 17.79, + "temperatureDewPoint": 6.76, + "uvIndex": 2, + "visibility": 30544, + "windDirection": 24, + "windGust": 17.27, + "windSpeed": 9.93 + }, + { + "forecastStart": "2026-01-19T23:00:00Z", + "cloudCover": 0.05, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.48, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.78, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.38, + "temperatureApparent": 18.35, + "temperatureDewPoint": 6.26, + "uvIndex": 1, + "visibility": 30235, + "windDirection": 23, + "windGust": 17.91, + "windSpeed": 9.57 + }, + { + "forecastStart": "2026-01-20T00:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.49, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.59, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.22, + "temperatureApparent": 17.99, + "temperatureDewPoint": 6.41, + "uvIndex": 0, + "visibility": 29939, + "windDirection": 20, + "windGust": 16.55, + "windSpeed": 8.69 + }, + { + "forecastStart": "2026-01-20T01:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.52, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.62, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.18, + "temperatureApparent": 14.85, + "temperatureDewPoint": 6.31, + "uvIndex": 0, + "visibility": 29604, + "windDirection": 15, + "windGust": 14.34, + "windSpeed": 7.54 + }, + { + "forecastStart": "2026-01-20T02:00:00Z", + "cloudCover": 0.03, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.56, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.91, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.86, + "temperatureApparent": 13.01, + "temperatureDewPoint": 6.16, + "uvIndex": 0, + "visibility": 28795, + "windDirection": 12, + "windGust": 12.98, + "windSpeed": 7.14 + }, + { + "forecastStart": "2026-01-20T03:00:00Z", + "cloudCover": 0.03, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.6, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.2, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.69, + "temperatureApparent": 11.8, + "temperatureDewPoint": 6.06, + "uvIndex": 0, + "visibility": 27947, + "windDirection": 17, + "windGust": 12.37, + "windSpeed": 7.12 + }, + { + "forecastStart": "2026-01-20T04:00:00Z", + "cloudCover": 0.03, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.64, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.45, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.71, + "temperatureApparent": 10.68, + "temperatureDewPoint": 6.07, + "uvIndex": 0, + "visibility": 27449, + "windDirection": 21, + "windGust": 13.02, + "windSpeed": 7.45 + }, + { + "forecastStart": "2026-01-20T05:00:00Z", + "cloudCover": 0.04, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.68, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.69, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.64, + "temperatureApparent": 9.51, + "temperatureDewPoint": 5.93, + "uvIndex": 0, + "visibility": 27330, + "windDirection": 26, + "windGust": 13.61, + "windSpeed": 7.72 + }, + { + "forecastStart": "2026-01-20T06:00:00Z", + "cloudCover": 0.04, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.92, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.84, + "temperatureApparent": 8.69, + "temperatureDewPoint": 5.99, + "uvIndex": 0, + "visibility": 26377, + "windDirection": 30, + "windGust": 13.95, + "windSpeed": 7.92 + }, + { + "forecastStart": "2026-01-20T07:00:00Z", + "cloudCover": 0.01, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.75, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.65, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.99, + "temperatureApparent": 7.81, + "temperatureDewPoint": 5.76, + "uvIndex": 0, + "visibility": 27658, + "windDirection": 29, + "windGust": 14.76, + "windSpeed": 7.95 + }, + { + "forecastStart": "2026-01-20T08:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.69, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.39, + "temperatureApparent": 7.26, + "temperatureDewPoint": 5.75, + "uvIndex": 0, + "visibility": 26837, + "windDirection": 32, + "windGust": 14.44, + "windSpeed": 7.91 + }, + { + "forecastStart": "2026-01-20T09:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.67, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.86, + "temperatureApparent": 6.63, + "temperatureDewPoint": 5.6, + "uvIndex": 0, + "visibility": 25655, + "windDirection": 35, + "windGust": 14.58, + "windSpeed": 8.21 + }, + { + "forecastStart": "2026-01-20T10:00:00Z", + "cloudCover": 0.05, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.64, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.39, + "temperatureApparent": 6.09, + "temperatureDewPoint": 5.67, + "uvIndex": 0, + "visibility": 23659, + "windDirection": 36, + "windGust": 15.14, + "windSpeed": 8.54 + }, + { + "forecastStart": "2026-01-20T11:00:00Z", + "cloudCover": 0.08, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.54, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.01, + "temperatureApparent": 5.55, + "temperatureDewPoint": 5.64, + "uvIndex": 0, + "visibility": 21303, + "windDirection": 38, + "windGust": 16.04, + "windSpeed": 9.07 + }, + { + "forecastStart": "2026-01-20T12:00:00Z", + "cloudCover": 0.11, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.5, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.74, + "temperatureApparent": 5.2, + "temperatureDewPoint": 5.55, + "uvIndex": 0, + "visibility": 19499, + "windDirection": 41, + "windGust": 16.49, + "windSpeed": 9.39 + }, + { + "forecastStart": "2026-01-20T13:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.58, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.54, + "temperatureApparent": 4.96, + "temperatureDewPoint": 5.52, + "uvIndex": 0, + "visibility": 18464, + "windDirection": 44, + "windGust": 16.21, + "windSpeed": 9.52 + }, + { + "forecastStart": "2026-01-20T14:00:00Z", + "cloudCover": 0.13, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.77, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.43, + "temperatureApparent": 4.85, + "temperatureDewPoint": 5.41, + "uvIndex": 0, + "visibility": 17980, + "windDirection": 47, + "windGust": 15.64, + "windSpeed": 9.54 + }, + { + "forecastStart": "2026-01-20T15:00:00Z", + "cloudCover": 0.14, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.06, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.95, + "temperatureApparent": 5.41, + "temperatureDewPoint": 5.75, + "uvIndex": 0, + "visibility": 18313, + "windDirection": 50, + "windGust": 15.26, + "windSpeed": 9.45 + }, + { + "forecastStart": "2026-01-20T16:00:00Z", + "cloudCover": 0.16, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.45, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.37, + "temperatureApparent": 7.44, + "temperatureDewPoint": 5.82, + "uvIndex": 0, + "visibility": 19824, + "windDirection": 51, + "windGust": 15.29, + "windSpeed": 9.48 + }, + { + "forecastStart": "2026-01-20T17:00:00Z", + "cloudCover": 0.17, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.81, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.85, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.12, + "temperatureApparent": 9.63, + "temperatureDewPoint": 6.03, + "uvIndex": 1, + "visibility": 22154, + "windDirection": 51, + "windGust": 15.42, + "windSpeed": 9.37 + }, + { + "forecastStart": "2026-01-20T18:00:00Z", + "cloudCover": 0.17, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.03, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.19, + "temperatureApparent": 11.03, + "temperatureDewPoint": 6.15, + "uvIndex": 1, + "visibility": 24487, + "windDirection": 50, + "windGust": 15.53, + "windSpeed": 9.15 + }, + { + "forecastStart": "2026-01-20T19:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.78, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.79, + "temperatureApparent": 12.7, + "temperatureDewPoint": 6.7, + "uvIndex": 2, + "visibility": 26742, + "windDirection": 47, + "windGust": 16.28, + "windSpeed": 9.03 + }, + { + "forecastStart": "2026-01-20T20:00:00Z", + "cloudCover": 0.06, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.65, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.15, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.68, + "temperatureApparent": 14.93, + "temperatureDewPoint": 7.22, + "uvIndex": 3, + "visibility": 28998, + "windDirection": 41, + "windGust": 17.42, + "windSpeed": 8.85 + }, + { + "forecastStart": "2026-01-20T21:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.6, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.54, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.23, + "temperatureApparent": 16.75, + "temperatureDewPoint": 7.51, + "uvIndex": 3, + "visibility": 30680, + "windDirection": 35, + "windGust": 18.28, + "windSpeed": 8.56 + }, + { + "forecastStart": "2026-01-20T22:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.56, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.15, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.31, + "temperatureApparent": 18.02, + "temperatureDewPoint": 7.51, + "uvIndex": 2, + "visibility": 31487, + "windDirection": 27, + "windGust": 18.66, + "windSpeed": 7.94 + }, + { + "forecastStart": "2026-01-20T23:00:00Z", + "cloudCover": 0.04, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.52, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.86, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.06, + "temperatureApparent": 18.71, + "temperatureDewPoint": 7.13, + "uvIndex": 1, + "visibility": 31721, + "windDirection": 20, + "windGust": 18.87, + "windSpeed": 7.46 + }, + { + "forecastStart": "2026-01-21T00:00:00Z", + "cloudCover": 0.06, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.51, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.71, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 17.21, + "temperatureApparent": 18.42, + "temperatureDewPoint": 6.98, + "uvIndex": 0, + "visibility": 31712, + "windDirection": 14, + "windGust": 18.44, + "windSpeed": 6.98 + }, + { + "forecastStart": "2026-01-21T01:00:00Z", + "cloudCover": 0.08, + "conditionCode": "Clear", + "daylight": true, + "humidity": 0.52, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.76, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.38, + "temperatureApparent": 15.33, + "temperatureDewPoint": 6.5, + "uvIndex": 0, + "visibility": 31503, + "windDirection": 11, + "windGust": 17.25, + "windSpeed": 6.99 + }, + { + "forecastStart": "2026-01-21T02:00:00Z", + "cloudCover": 0.1, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.55, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.04, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.05, + "temperatureApparent": 13.35, + "temperatureDewPoint": 6.08, + "uvIndex": 0, + "visibility": 31051, + "windDirection": 14, + "windGust": 15.12, + "windSpeed": 6.9 + }, + { + "forecastStart": "2026-01-21T03:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.58, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.31, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.82, + "temperatureApparent": 12.11, + "temperatureDewPoint": 5.7, + "uvIndex": 0, + "visibility": 30557, + "windDirection": 17, + "windGust": 13.61, + "windSpeed": 6.78 + }, + { + "forecastStart": "2026-01-21T04:00:00Z", + "cloudCover": 0.12, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.61, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.52, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.85, + "temperatureApparent": 11.23, + "temperatureDewPoint": 5.51, + "uvIndex": 0, + "visibility": 30195, + "windDirection": 21, + "windGust": 12.2, + "windSpeed": 6.38 + }, + { + "forecastStart": "2026-01-21T05:00:00Z", + "cloudCover": 0.11, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.65, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.69, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.95, + "temperatureApparent": 10.43, + "temperatureDewPoint": 5.57, + "uvIndex": 0, + "visibility": 29791, + "windDirection": 29, + "windGust": 10.98, + "windSpeed": 5.99 + }, + { + "forecastStart": "2026-01-21T06:00:00Z", + "cloudCover": 0.1, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.69, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.81, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.14, + "temperatureApparent": 9.68, + "temperatureDewPoint": 5.66, + "uvIndex": 0, + "visibility": 29023, + "windDirection": 33, + "windGust": 10.43, + "windSpeed": 5.95 + }, + { + "forecastStart": "2026-01-21T07:00:00Z", + "cloudCover": 0.09, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.9, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.11, + "temperatureApparent": 8.74, + "temperatureDewPoint": 5.29, + "uvIndex": 0, + "visibility": 27595, + "windDirection": 39, + "windGust": 10.03, + "windSpeed": 5.79 + }, + { + "forecastStart": "2026-01-21T08:00:00Z", + "cloudCover": 0.07, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.95, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.46, + "temperatureApparent": 8.11, + "temperatureDewPoint": 5.06, + "uvIndex": 0, + "visibility": 25805, + "windDirection": 42, + "windGust": 9.88, + "windSpeed": 5.77 + }, + { + "forecastStart": "2026-01-21T09:00:00Z", + "cloudCover": 0.06, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.91, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.87, + "temperatureApparent": 7.46, + "temperatureDewPoint": 4.87, + "uvIndex": 0, + "visibility": 24225, + "windDirection": 42, + "windGust": 10.22, + "windSpeed": 6 + }, + { + "forecastStart": "2026-01-21T10:00:00Z", + "cloudCover": 0.07, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.89, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.29, + "temperatureApparent": 6.87, + "temperatureDewPoint": 4.86, + "uvIndex": 0, + "visibility": 23260, + "windDirection": 42, + "windGust": 10.7, + "windSpeed": 6.13 + }, + { + "forecastStart": "2026-01-21T11:00:00Z", + "cloudCover": 0.08, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.81, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.77, + "temperatureApparent": 6.32, + "temperatureDewPoint": 4.89, + "uvIndex": 0, + "visibility": 22502, + "windDirection": 41, + "windGust": 11.53, + "windSpeed": 6.35 + }, + { + "forecastStart": "2026-01-21T12:00:00Z", + "cloudCover": 0.1, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.79, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.37, + "temperatureApparent": 5.86, + "temperatureDewPoint": 4.84, + "uvIndex": 0, + "visibility": 21302, + "windDirection": 41, + "windGust": 12.22, + "windSpeed": 6.63 + }, + { + "forecastStart": "2026-01-21T13:00:00Z", + "cloudCover": 0.16, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.9, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.06, + "temperatureApparent": 5.63, + "temperatureDewPoint": 4.88, + "uvIndex": 0, + "visibility": 18790, + "windDirection": 41, + "windGust": 12.1, + "windSpeed": 6.68 + }, + { + "forecastStart": "2026-01-21T14:00:00Z", + "cloudCover": 0.25, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.11, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 6.87, + "temperatureApparent": 5.49, + "temperatureDewPoint": 5.02, + "uvIndex": 0, + "visibility": 15835, + "windDirection": 41, + "windGust": 11.92, + "windSpeed": 6.88 + }, + { + "forecastStart": "2026-01-21T15:00:00Z", + "cloudCover": 0.28, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.35, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 6.96, + "temperatureApparent": 5.55, + "temperatureDewPoint": 5.11, + "uvIndex": 0, + "visibility": 14394, + "windDirection": 42, + "windGust": 12.16, + "windSpeed": 7.08 + }, + { + "forecastStart": "2026-01-21T16:00:00Z", + "cloudCover": 0.26, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.69, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 7.37, + "temperatureApparent": 7.36, + "temperatureDewPoint": 5.18, + "uvIndex": 0, + "visibility": 15702, + "windDirection": 42, + "windGust": 12.72, + "windSpeed": 7.03 + }, + { + "forecastStart": "2026-01-21T17:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.04, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.05, + "temperatureApparent": 9.18, + "temperatureDewPoint": 5.34, + "uvIndex": 1, + "visibility": 18530, + "windDirection": 42, + "windGust": 13.77, + "windSpeed": 7.07 + }, + { + "forecastStart": "2026-01-21T18:00:00Z", + "cloudCover": 0.31, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.18, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.06, + "temperatureApparent": 10.2, + "temperatureDewPoint": 5.61, + "uvIndex": 2, + "visibility": 21149, + "windDirection": 41, + "windGust": 14.67, + "windSpeed": 7.11 + }, + { + "forecastStart": "2026-01-21T19:00:00Z", + "cloudCover": 0.28, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.89, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.94, + "temperatureApparent": 12.09, + "temperatureDewPoint": 6.49, + "uvIndex": 2, + "visibility": 22907, + "windDirection": 36, + "windGust": 15.53, + "windSpeed": 7.08 + }, + { + "forecastStart": "2026-01-21T20:00:00Z", + "cloudCover": 0.23, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.68, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.36, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.7, + "temperatureApparent": 13.95, + "temperatureDewPoint": 6.94, + "uvIndex": 3, + "visibility": 24459, + "windDirection": 30, + "windGust": 16.34, + "windSpeed": 6.99 + }, + { + "forecastStart": "2026-01-21T21:00:00Z", + "cloudCover": 0.2, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.64, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.86, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.15, + "temperatureApparent": 15.56, + "temperatureDewPoint": 7.44, + "uvIndex": 3, + "visibility": 26033, + "windDirection": 23, + "windGust": 16.74, + "windSpeed": 6.85 + }, + { + "forecastStart": "2026-01-21T22:00:00Z", + "cloudCover": 0.21, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.6, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.43, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.23, + "temperatureApparent": 16.67, + "temperatureDewPoint": 7.51, + "uvIndex": 2, + "visibility": 27965, + "windDirection": 14, + "windGust": 16.53, + "windSpeed": 6.64 + }, + { + "forecastStart": "2026-01-21T23:00:00Z", + "cloudCover": 0.22, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.58, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.04, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.01, + "temperatureApparent": 17.41, + "temperatureDewPoint": 7.75, + "uvIndex": 1, + "visibility": 29914, + "windDirection": 3, + "windGust": 15.91, + "windSpeed": 6.38 + }, + { + "forecastStart": "2026-01-22T00:00:00Z", + "cloudCover": 0.25, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.57, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.83, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 16.21, + "temperatureApparent": 17.25, + "temperatureDewPoint": 7.68, + "uvIndex": 0, + "visibility": 31104, + "windDirection": 354, + "windGust": 15.03, + "windSpeed": 6.06 + }, + { + "forecastStart": "2026-01-22T01:00:00Z", + "cloudCover": 0.3, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.59, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.91, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 15.44, + "temperatureApparent": 14.91, + "temperatureDewPoint": 7.46, + "uvIndex": 0, + "visibility": 31045, + "windDirection": 348, + "windGust": 13.77, + "windSpeed": 5.71 + }, + { + "forecastStart": "2026-01-22T02:00:00Z", + "cloudCover": 0.35, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.63, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.18, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 14.07, + "temperatureApparent": 13.18, + "temperatureDewPoint": 7.13, + "uvIndex": 0, + "visibility": 30229, + "windDirection": 342, + "windGust": 12.24, + "windSpeed": 5.3 + }, + { + "forecastStart": "2026-01-22T03:00:00Z", + "cloudCover": 0.38, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.67, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.42, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.83, + "temperatureApparent": 12.09, + "temperatureDewPoint": 6.85, + "uvIndex": 0, + "visibility": 29353, + "windDirection": 339, + "windGust": 11.04, + "windSpeed": 4.8 + }, + { + "forecastStart": "2026-01-22T04:00:00Z", + "cloudCover": 0.38, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.7, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.59, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.95, + "temperatureApparent": 11.43, + "temperatureDewPoint": 6.65, + "uvIndex": 0, + "visibility": 28661, + "windDirection": 347, + "windGust": 10.44, + "windSpeed": 4.02 + }, + { + "forecastStart": "2026-01-22T05:00:00Z", + "cloudCover": 0.36, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.75, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.19, + "temperatureApparent": 10.96, + "temperatureDewPoint": 6.53, + "uvIndex": 0, + "visibility": 27909, + "windDirection": 11, + "windGust": 10.16, + "windSpeed": 3.15 + }, + { + "forecastStart": "2026-01-22T06:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.83, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.27, + "temperatureApparent": 10.2, + "temperatureDewPoint": 6.22, + "uvIndex": 0, + "visibility": 27054, + "windDirection": 39, + "windGust": 9.96, + "windSpeed": 2.73 + }, + { + "forecastStart": "2026-01-22T07:00:00Z", + "cloudCover": 0.39, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.82, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.68, + "temperatureApparent": 9.64, + "temperatureDewPoint": 6.4, + "uvIndex": 0, + "visibility": 26223, + "windDirection": 50, + "windGust": 9.8, + "windSpeed": 3.15 + }, + { + "forecastStart": "2026-01-22T08:00:00Z", + "cloudCover": 0.46, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.73, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.19, + "temperatureApparent": 9.05, + "temperatureDewPoint": 6.45, + "uvIndex": 0, + "visibility": 25289, + "windDirection": 50, + "windGust": 9.71, + "windSpeed": 4.02 + }, + { + "forecastStart": "2026-01-22T09:00:00Z", + "cloudCover": 0.5, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.59, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.06, + "temperatureApparent": 8.8, + "temperatureDewPoint": 6.67, + "uvIndex": 0, + "visibility": 23825, + "windDirection": 51, + "windGust": 9.67, + "windSpeed": 4.68 + }, + { + "forecastStart": "2026-01-22T10:00:00Z", + "cloudCover": 0.51, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.36, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.69, + "temperatureApparent": 8.4, + "temperatureDewPoint": 6.65, + "uvIndex": 0, + "visibility": 21214, + "windDirection": 53, + "windGust": 9.63, + "windSpeed": 4.89 + }, + { + "forecastStart": "2026-01-22T11:00:00Z", + "cloudCover": 0.52, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.89, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.08, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.41, + "temperatureApparent": 8.15, + "temperatureDewPoint": 6.7, + "uvIndex": 0, + "visibility": 18067, + "windDirection": 54, + "windGust": 9.62, + "windSpeed": 4.9 + }, + { + "forecastStart": "2026-01-22T12:00:00Z", + "cloudCover": 0.52, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.89, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.93, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.25, + "temperatureApparent": 8.01, + "temperatureDewPoint": 6.54, + "uvIndex": 0, + "visibility": 15812, + "windDirection": 57, + "windGust": 9.72, + "windSpeed": 4.87 + }, + { + "forecastStart": "2026-01-22T13:00:00Z", + "cloudCover": 0.52, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.89, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.97, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.15, + "temperatureApparent": 7.93, + "temperatureDewPoint": 6.45, + "uvIndex": 0, + "visibility": 14785, + "windDirection": 65, + "windGust": 9.87, + "windSpeed": 4.83 + }, + { + "forecastStart": "2026-01-22T14:00:00Z", + "cloudCover": 0.52, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.14, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.11, + "temperatureApparent": 7.92, + "temperatureDewPoint": 6.24, + "uvIndex": 0, + "visibility": 14306, + "windDirection": 72, + "windGust": 10.02, + "windSpeed": 4.72 + }, + { + "forecastStart": "2026-01-22T15:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.38, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.26, + "temperatureApparent": 8.13, + "temperatureDewPoint": 6.22, + "uvIndex": 0, + "visibility": 14279, + "windDirection": 75, + "windGust": 10.3, + "windSpeed": 4.54 + }, + { + "forecastStart": "2026-01-22T16:00:00Z", + "cloudCover": 0.55, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.71, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.6, + "temperatureApparent": 9.36, + "temperatureDewPoint": 6.39, + "uvIndex": 0, + "visibility": 14610, + "windDirection": 71, + "windGust": 10.77, + "windSpeed": 4.13 + }, + { + "forecastStart": "2026-01-22T17:00:00Z", + "cloudCover": 0.58, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.02, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.09, + "temperatureApparent": 10.43, + "temperatureDewPoint": 6.35, + "uvIndex": 1, + "visibility": 15201, + "windDirection": 62, + "windGust": 11.39, + "windSpeed": 3.65 + }, + { + "forecastStart": "2026-01-22T18:00:00Z", + "cloudCover": 0.6, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.81, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.09, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.65, + "temperatureApparent": 10.96, + "temperatureDewPoint": 6.55, + "uvIndex": 1, + "visibility": 15950, + "windDirection": 51, + "windGust": 12.09, + "windSpeed": 3.57 + }, + { + "forecastStart": "2026-01-22T19:00:00Z", + "cloudCover": 0.62, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.79, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.39, + "temperatureApparent": 11.33, + "temperatureDewPoint": 6.72, + "uvIndex": 2, + "visibility": 17166, + "windDirection": 35, + "windGust": 12.96, + "windSpeed": 4.21 + }, + { + "forecastStart": "2026-01-22T20:00:00Z", + "cloudCover": 0.63, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.24, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.32, + "temperatureApparent": 11.77, + "temperatureDewPoint": 7.24, + "uvIndex": 3, + "visibility": 18988, + "windDirection": 6, + "windGust": 14.12, + "windSpeed": 5.28 + }, + { + "forecastStart": "2026-01-22T21:00:00Z", + "cloudCover": 0.64, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.68, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.84, + "temperatureApparent": 11.84, + "temperatureDewPoint": 7.35, + "uvIndex": 2, + "visibility": 21062, + "windDirection": 338, + "windGust": 15.52, + "windSpeed": 6.32 + }, + { + "forecastStart": "2026-01-22T22:00:00Z", + "cloudCover": 0.63, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.19, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.82, + "temperatureApparent": 12.58, + "temperatureDewPoint": 7.9, + "uvIndex": 2, + "visibility": 23035, + "windDirection": 318, + "windGust": 17.06, + "windSpeed": 7.24 + }, + { + "forecastStart": "2026-01-22T23:00:00Z", + "cloudCover": 0.62, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.76, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.26, + "temperatureApparent": 12.77, + "temperatureDewPoint": 8.11, + "uvIndex": 1, + "visibility": 24557, + "windDirection": 303, + "windGust": 18.41, + "windSpeed": 8.1 + }, + { + "forecastStart": "2026-01-23T00:00:00Z", + "cloudCover": 0.63, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.47, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.39, + "temperatureApparent": 12.62, + "temperatureDewPoint": 8.24, + "uvIndex": 0, + "visibility": 25276, + "windDirection": 296, + "windGust": 19.16, + "windSpeed": 8.56 + }, + { + "forecastStart": "2026-01-23T01:00:00Z", + "cloudCover": 0.65, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.38, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.02, + "temperatureApparent": 11.78, + "temperatureDewPoint": 8.09, + "uvIndex": 0, + "visibility": 25093, + "windDirection": 293, + "windGust": 19.16, + "windSpeed": 8.38 + }, + { + "forecastStart": "2026-01-23T02:00:00Z", + "cloudCover": 0.68, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.75, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.4, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.36, + "temperatureApparent": 11.14, + "temperatureDewPoint": 8.05, + "uvIndex": 0, + "visibility": 24270, + "windDirection": 293, + "windGust": 18.59, + "windSpeed": 7.79 + }, + { + "forecastStart": "2026-01-23T03:00:00Z", + "cloudCover": 0.7, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.77, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.45, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.65, + "temperatureApparent": 10.67, + "temperatureDewPoint": 7.75, + "uvIndex": 0, + "visibility": 22996, + "windDirection": 291, + "windGust": 17.51, + "windSpeed": 7.17 + }, + { + "forecastStart": "2026-01-23T04:00:00Z", + "cloudCover": 0.72, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.47, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.03, + "temperatureApparent": 10.3, + "temperatureDewPoint": 7.53, + "uvIndex": 0, + "visibility": 21461, + "windDirection": 287, + "windGust": 16, + "windSpeed": 6.62 + }, + { + "forecastStart": "2026-01-23T05:00:00Z", + "cloudCover": 0.72, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.81, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.45, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.47, + "temperatureApparent": 9.94, + "temperatureDewPoint": 7.35, + "uvIndex": 0, + "visibility": 19858, + "windDirection": 282, + "windGust": 14.37, + "windSpeed": 6.09 + }, + { + "forecastStart": "2026-01-23T06:00:00Z", + "cloudCover": 0.71, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.37, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.4, + "temperatureApparent": 9.98, + "temperatureDewPoint": 7.46, + "uvIndex": 0, + "visibility": 18376, + "windDirection": 278, + "windGust": 13.1, + "windSpeed": 5.8 + }, + { + "forecastStart": "2026-01-23T07:00:00Z", + "cloudCover": 0.69, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.21, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.81, + "temperatureApparent": 9.35, + "temperatureDewPoint": 7.06, + "uvIndex": 0, + "visibility": 16860, + "windDirection": 278, + "windGust": 12.27, + "windSpeed": 5.89 + }, + { + "forecastStart": "2026-01-23T08:00:00Z", + "cloudCover": 0.66, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.55, + "temperatureApparent": 8.95, + "temperatureDewPoint": 6.98, + "uvIndex": 0, + "visibility": 15128, + "windDirection": 281, + "windGust": 11.62, + "windSpeed": 6.2 + }, + { + "forecastStart": "2026-01-23T09:00:00Z", + "cloudCover": 0.66, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.78, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.31, + "temperatureApparent": 8.63, + "temperatureDewPoint": 6.92, + "uvIndex": 0, + "visibility": 13333, + "windDirection": 288, + "windGust": 11.11, + "windSpeed": 6.48 + }, + { + "forecastStart": "2026-01-23T10:00:00Z", + "cloudCover": 0.68, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.56, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.04, + "temperatureApparent": 8.33, + "temperatureDewPoint": 6.82, + "uvIndex": 0, + "visibility": 11627, + "windDirection": 302, + "windGust": 10.69, + "windSpeed": 6.66 + }, + { + "forecastStart": "2026-01-23T11:00:00Z", + "cloudCover": 0.73, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.37, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.74, + "temperatureApparent": 8.06, + "temperatureDewPoint": 6.7, + "uvIndex": 0, + "visibility": 10162, + "windDirection": 318, + "windGust": 10.35, + "windSpeed": 6.77 + }, + { + "forecastStart": "2026-01-23T12:00:00Z", + "cloudCover": 0.77, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.24, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.49, + "temperatureApparent": 7.91, + "temperatureDewPoint": 6.62, + "uvIndex": 0, + "visibility": 9086, + "windDirection": 330, + "windGust": 10.01, + "windSpeed": 6.68 + }, + { + "forecastStart": "2026-01-23T13:00:00Z", + "cloudCover": 0.7, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.25, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.78, + "temperatureApparent": 8.26, + "temperatureDewPoint": 6.9, + "uvIndex": 0, + "visibility": 10809, + "windDirection": 342, + "windGust": 7.91, + "windSpeed": 6.27 + }, + { + "forecastStart": "2026-01-23T14:00:00Z", + "cloudCover": 0.72, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.44, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.67, + "temperatureApparent": 8.41, + "temperatureDewPoint": 6.79, + "uvIndex": 0, + "visibility": 10815, + "windDirection": 356, + "windGust": 8.44, + "windSpeed": 5.65 + }, + { + "forecastStart": "2026-01-23T15:00:00Z", + "cloudCover": 0.72, + "conditionCode": "MostlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.67, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.74, + "temperatureApparent": 8.69, + "temperatureDewPoint": 6.86, + "uvIndex": 0, + "visibility": 10822, + "windDirection": 11, + "windGust": 8.81, + "windSpeed": 5.06 + }, + { + "forecastStart": "2026-01-23T16:00:00Z", + "cloudCover": 0.7, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.99, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.06, + "temperatureApparent": 9.49, + "temperatureDewPoint": 6.84, + "uvIndex": 0, + "visibility": 10829, + "windDirection": 27, + "windGust": 8.93, + "windSpeed": 4.56 + }, + { + "forecastStart": "2026-01-23T17:00:00Z", + "cloudCover": 0.66, + "conditionCode": "MostlyCloudy", + "daylight": true, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.32, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.34, + "temperatureApparent": 10.23, + "temperatureDewPoint": 6.77, + "uvIndex": 1, + "visibility": 11555, + "windDirection": 41, + "windGust": 8.95, + "windSpeed": 4.15 + }, + { + "forecastStart": "2026-01-23T18:00:00Z", + "cloudCover": 0.61, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.42, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.95, + "temperatureApparent": 11.09, + "temperatureDewPoint": 7.02, + "uvIndex": 1, + "visibility": 12422, + "windDirection": 44, + "windGust": 9.04, + "windSpeed": 3.95 + }, + { + "forecastStart": "2026-01-23T19:00:00Z", + "cloudCover": 0.56, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.15, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.71, + "temperatureApparent": 11.94, + "temperatureDewPoint": 7.22, + "uvIndex": 2, + "visibility": 13549, + "windDirection": 30, + "windGust": 9.24, + "windSpeed": 3.97 + }, + { + "forecastStart": "2026-01-23T20:00:00Z", + "cloudCover": 0.49, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.66, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.59, + "temperatureApparent": 12.88, + "temperatureDewPoint": 7.5, + "uvIndex": 3, + "visibility": 15058, + "windDirection": 3, + "windGust": 9.57, + "windSpeed": 4.22 + }, + { + "forecastStart": "2026-01-23T21:00:00Z", + "cloudCover": 0.42, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.16, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12, + "temperatureApparent": 13.32, + "temperatureDewPoint": 7.51, + "uvIndex": 3, + "visibility": 16789, + "windDirection": 332, + "windGust": 10.16, + "windSpeed": 4.76 + }, + { + "forecastStart": "2026-01-23T22:00:00Z", + "cloudCover": 0.38, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.74, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.52, + "temperatureApparent": 13.68, + "temperatureDewPoint": 7.61, + "uvIndex": 2, + "visibility": 18577, + "windDirection": 294, + "windGust": 10.99, + "windSpeed": 5.73 + }, + { + "forecastStart": "2026-01-23T23:00:00Z", + "cloudCover": 0.36, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.72, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.37, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.9, + "temperatureApparent": 13.72, + "temperatureDewPoint": 7.97, + "uvIndex": 1, + "visibility": 20262, + "windDirection": 270, + "windGust": 11.84, + "windSpeed": 6.91 + }, + { + "forecastStart": "2026-01-24T00:00:00Z", + "cloudCover": 0.32, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.12, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13, + "temperatureApparent": 13.37, + "temperatureDewPoint": 7.86, + "uvIndex": 0, + "visibility": 21684, + "windDirection": 263, + "windGust": 12.56, + "windSpeed": 7.83 + }, + { + "forecastStart": "2026-01-24T01:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1013.45, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.71, + "temperatureApparent": 11.24, + "temperatureDewPoint": 8.59, + "uvIndex": 0, + "visibility": 23024, + "windDirection": 258, + "windGust": 13.2, + "windSpeed": 9.03 + }, + { + "forecastStart": "2026-01-24T02:00:00Z", + "cloudCover": 0.11, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1013.63, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.16, + "temperatureApparent": 9.78, + "temperatureDewPoint": 8.44, + "uvIndex": 0, + "visibility": 24450, + "windDirection": 261, + "windGust": 13.73, + "windSpeed": 9.18 + }, + { + "forecastStart": "2026-01-24T03:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1013.8, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.59, + "temperatureApparent": 9.03, + "temperatureDewPoint": 8.26, + "uvIndex": 0, + "visibility": 25772, + "windDirection": 264, + "windGust": 13.85, + "windSpeed": 9.31 + }, + { + "forecastStart": "2026-01-24T04:00:00Z", + "cloudCover": 0, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1013.91, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.12, + "temperatureApparent": 8.49, + "temperatureDewPoint": 8.16, + "uvIndex": 0, + "visibility": 26805, + "windDirection": 264, + "windGust": 13.44, + "windSpeed": 9.51 + }, + { + "forecastStart": "2026-01-24T05:00:00Z", + "cloudCover": 0.02, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1013.99, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.71, + "temperatureApparent": 8.02, + "temperatureDewPoint": 8.12, + "uvIndex": 0, + "visibility": 27362, + "windDirection": 263, + "windGust": 12.79, + "windSpeed": 9.74 + }, + { + "forecastStart": "2026-01-24T06:00:00Z", + "cloudCover": 0.08, + "conditionCode": "Clear", + "daylight": false, + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.04, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.39, + "temperatureApparent": 7.68, + "temperatureDewPoint": 7.98, + "uvIndex": 0, + "visibility": 27258, + "windDirection": 263, + "windGust": 12.25, + "windSpeed": 10 + }, + { + "forecastStart": "2026-01-24T07:00:00Z", + "cloudCover": 0.2, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.07, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.13, + "temperatureApparent": 7.46, + "temperatureDewPoint": 7.89, + "uvIndex": 0, + "visibility": 26118, + "windDirection": 264, + "windGust": 11.76, + "windSpeed": 10.32 + }, + { + "forecastStart": "2026-01-24T08:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.08, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.91, + "temperatureApparent": 7.3, + "temperatureDewPoint": 7.85, + "uvIndex": 0, + "visibility": 24022, + "windDirection": 266, + "windGust": 11.23, + "windSpeed": 10.62 + }, + { + "forecastStart": "2026-01-24T09:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.09, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.72, + "temperatureApparent": 7.18, + "temperatureDewPoint": 7.66, + "uvIndex": 0, + "visibility": 21462, + "windDirection": 267, + "windGust": 10.98, + "windSpeed": 10.77 + }, + { + "forecastStart": "2026-01-24T10:00:00Z", + "cloudCover": 0.41, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.06, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.62, + "temperatureApparent": 7.03, + "temperatureDewPoint": 7.39, + "uvIndex": 0, + "visibility": 18928, + "windDirection": 267, + "windGust": 11.25, + "windSpeed": 10.75 + }, + { + "forecastStart": "2026-01-24T11:00:00Z", + "cloudCover": 0.32, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.85, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.06, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.45, + "temperatureApparent": 6.78, + "temperatureDewPoint": 7.05, + "uvIndex": 0, + "visibility": 16908, + "windDirection": 266, + "windGust": 11.89, + "windSpeed": 10.6 + }, + { + "forecastStart": "2026-01-24T12:00:00Z", + "cloudCover": 0.25, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.2, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.31, + "temperatureApparent": 6.67, + "temperatureDewPoint": 6.74, + "uvIndex": 0, + "visibility": 15886, + "windDirection": 264, + "windGust": 12.6, + "windSpeed": 10.24 + }, + { + "forecastStart": "2026-01-24T13:00:00Z", + "cloudCover": 0.28, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1014.55, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.95, + "temperatureApparent": 6.69, + "temperatureDewPoint": 6.39, + "uvIndex": 0, + "visibility": 15944, + "windDirection": 261, + "windGust": 13.24, + "windSpeed": 9.29 + }, + { + "forecastStart": "2026-01-24T14:00:00Z", + "cloudCover": 0.31, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.05, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.53, + "temperatureApparent": 6.75, + "temperatureDewPoint": 5.98, + "uvIndex": 0, + "visibility": 16708, + "windDirection": 255, + "windGust": 13.99, + "windSpeed": 8.12 + }, + { + "forecastStart": "2026-01-24T15:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1015.65, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.31, + "temperatureApparent": 6.69, + "temperatureDewPoint": 5.76, + "uvIndex": 0, + "visibility": 17971, + "windDirection": 243, + "windGust": 14.96, + "windSpeed": 7.8 + }, + { + "forecastStart": "2026-01-24T16:00:00Z", + "cloudCover": 0.39, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1016.41, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.64, + "temperatureApparent": 7.67, + "temperatureDewPoint": 5.74, + "uvIndex": 0, + "visibility": 19529, + "windDirection": 264, + "windGust": 16.23, + "windSpeed": 9.16 + }, + { + "forecastStart": "2026-01-24T17:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.81, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.22, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.13, + "temperatureApparent": 7.96, + "temperatureDewPoint": 6.04, + "uvIndex": 1, + "visibility": 21178, + "windDirection": 27, + "windGust": 17.54, + "windSpeed": 11.37 + }, + { + "forecastStart": "2026-01-24T18:00:00Z", + "cloudCover": 0.46, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.76, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.67, + "temperatureApparent": 7.92, + "temperatureDewPoint": 6.2, + "uvIndex": 2, + "visibility": 22718, + "windDirection": 26, + "windGust": 18.53, + "windSpeed": 13.01 + }, + { + "forecastStart": "2026-01-24T19:00:00Z", + "cloudCover": 0.43, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.82, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.29, + "temperatureApparent": 8.47, + "temperatureDewPoint": 6.24, + "uvIndex": 2, + "visibility": 24368, + "windDirection": 18, + "windGust": 19.1, + "windSpeed": 13.53 + }, + { + "forecastStart": "2026-01-24T20:00:00Z", + "cloudCover": 0.37, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.61, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.11, + "temperatureApparent": 9.49, + "temperatureDewPoint": 6.65, + "uvIndex": 3, + "visibility": 26330, + "windDirection": 351, + "windGust": 19.55, + "windSpeed": 13.52 + }, + { + "forecastStart": "2026-01-24T21:00:00Z", + "cloudCover": 0.32, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.45, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.69, + "temperatureApparent": 10.3, + "temperatureDewPoint": 6.61, + "uvIndex": 3, + "visibility": 28380, + "windDirection": 314, + "windGust": 20.08, + "windSpeed": 13.35 + }, + { + "forecastStart": "2026-01-24T22:00:00Z", + "cloudCover": 0.29, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.7, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.47, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.12, + "temperatureApparent": 10.94, + "temperatureDewPoint": 6.81, + "uvIndex": 2, + "visibility": 30296, + "windDirection": 299, + "windGust": 20.81, + "windSpeed": 13.08 + }, + { + "forecastStart": "2026-01-24T23:00:00Z", + "cloudCover": 0.27, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.7, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.6, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.42, + "temperatureApparent": 11.47, + "temperatureDewPoint": 7.1, + "uvIndex": 1, + "visibility": 31858, + "windDirection": 293, + "windGust": 21.4, + "windSpeed": 12.56 + }, + { + "forecastStart": "2026-01-25T00:00:00Z", + "cloudCover": 0.26, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.7, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1017.83, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.49, + "temperatureApparent": 11.55, + "temperatureDewPoint": 7.17, + "uvIndex": 0, + "visibility": 32848, + "windDirection": 290, + "windGust": 21.37, + "windSpeed": 11.74 + }, + { + "forecastStart": "2026-01-25T01:00:00Z", + "cloudCover": 0.26, + "conditionCode": "MostlyClear", + "daylight": true, + "humidity": 0.71, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.2, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.17, + "temperatureApparent": 10.15, + "temperatureDewPoint": 7.07, + "uvIndex": 0, + "visibility": 33155, + "windDirection": 284, + "windGust": 20.32, + "windSpeed": 10.4 + }, + { + "forecastStart": "2026-01-25T02:00:00Z", + "cloudCover": 0.26, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1018.67, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.59, + "temperatureApparent": 9.46, + "temperatureDewPoint": 7.11, + "uvIndex": 0, + "visibility": 32934, + "windDirection": 278, + "windGust": 18.49, + "windSpeed": 8.74 + }, + { + "forecastStart": "2026-01-25T03:00:00Z", + "cloudCover": 0.28, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.17, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.99, + "temperatureApparent": 9.39, + "temperatureDewPoint": 6.92, + "uvIndex": 0, + "visibility": 32373, + "windDirection": 273, + "windGust": 16.36, + "windSpeed": 7.37 + }, + { + "forecastStart": "2026-01-25T04:00:00Z", + "cloudCover": 0.28, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.79, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1019.69, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.47, + "temperatureApparent": 9.15, + "temperatureDewPoint": 6.98, + "uvIndex": 0, + "visibility": 31653, + "windDirection": 275, + "windGust": 14.27, + "windSpeed": 6.67 + }, + { + "forecastStart": "2026-01-25T05:00:00Z", + "cloudCover": 0.3, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.21, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.98, + "temperatureApparent": 8.8, + "temperatureDewPoint": 7.05, + "uvIndex": 0, + "visibility": 30958, + "windDirection": 279, + "windGust": 12.45, + "windSpeed": 6.44 + }, + { + "forecastStart": "2026-01-25T06:00:00Z", + "cloudCover": 0.31, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.65, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.58, + "temperatureApparent": 8.47, + "temperatureDewPoint": 7.01, + "uvIndex": 0, + "visibility": 30466, + "windDirection": 281, + "windGust": 11.29, + "windSpeed": 6.37 + }, + { + "forecastStart": "2026-01-25T07:00:00Z", + "cloudCover": 0.34, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1020.96, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.25, + "temperatureApparent": 8.21, + "temperatureDewPoint": 7.03, + "uvIndex": 0, + "visibility": 30192, + "windDirection": 248, + "windGust": 10.89, + "windSpeed": 6.33 + }, + { + "forecastStart": "2026-01-25T08:00:00Z", + "cloudCover": 0.36, + "conditionCode": "MostlyClear", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.2, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.93, + "temperatureApparent": 7.91, + "temperatureDewPoint": 7.05, + "uvIndex": 0, + "visibility": 29994, + "windDirection": 192, + "windGust": 10.95, + "windSpeed": 6.39 + }, + { + "forecastStart": "2026-01-25T09:00:00Z", + "cloudCover": 0.4, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.41, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.71, + "temperatureApparent": 7.69, + "temperatureDewPoint": 6.83, + "uvIndex": 0, + "visibility": 29816, + "windDirection": 173, + "windGust": 11.23, + "windSpeed": 6.57 + }, + { + "forecastStart": "2026-01-25T10:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.9, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.6, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.53, + "temperatureApparent": 7.45, + "temperatureDewPoint": 6.98, + "uvIndex": 0, + "visibility": 29606, + "windDirection": 159, + "windGust": 11.48, + "windSpeed": 6.9 + }, + { + "forecastStart": "2026-01-25T11:00:00Z", + "cloudCover": 0.48, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.9, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1021.79, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.4, + "temperatureApparent": 7.23, + "temperatureDewPoint": 6.85, + "uvIndex": 0, + "visibility": 29310, + "windDirection": 135, + "windGust": 11.71, + "windSpeed": 7.29 + }, + { + "forecastStart": "2026-01-25T12:00:00Z", + "cloudCover": 0.51, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.91, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.01, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.32, + "temperatureApparent": 7.06, + "temperatureDewPoint": 6.94, + "uvIndex": 0, + "visibility": 28876, + "windDirection": 108, + "windGust": 12.05, + "windSpeed": 7.63 + }, + { + "forecastStart": "2026-01-25T13:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.91, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.25, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.36, + "temperatureApparent": 7.02, + "temperatureDewPoint": 6.98, + "uvIndex": 0, + "visibility": 28170, + "windDirection": 101, + "windGust": 12.83, + "windSpeed": 7.9 + }, + { + "forecastStart": "2026-01-25T14:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.91, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.52, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.47, + "temperatureApparent": 7.03, + "temperatureDewPoint": 7.08, + "uvIndex": 0, + "visibility": 27211, + "windDirection": 101, + "windGust": 13.98, + "windSpeed": 8.18 + }, + { + "forecastStart": "2026-01-25T15:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.9, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1022.85, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 8.74, + "temperatureApparent": 7.15, + "temperatureDewPoint": 7.19, + "uvIndex": 0, + "visibility": 26171, + "windDirection": 101, + "windGust": 15.04, + "windSpeed": 8.54 + }, + { + "forecastStart": "2026-01-25T16:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.34, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.24, + "temperatureApparent": 8.25, + "temperatureDewPoint": 7.35, + "uvIndex": 0, + "visibility": 25222, + "windDirection": 98, + "windGust": 15.62, + "windSpeed": 9.01 + }, + { + "forecastStart": "2026-01-25T17:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.87, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.95, + "temperatureApparent": 9.3, + "temperatureDewPoint": 7.72, + "uvIndex": 1, + "visibility": 24531, + "windDirection": 95, + "windGust": 15.8, + "windSpeed": 9.5 + }, + { + "forecastStart": "2026-01-25T18:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.83, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.18, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.66, + "temperatureApparent": 9.94, + "temperatureDewPoint": 7.89, + "uvIndex": 1, + "visibility": 24266, + "windDirection": 90, + "windGust": 15.87, + "windSpeed": 9.89 + }, + { + "forecastStart": "2026-01-25T19:00:00Z", + "cloudCover": 0.54, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.12, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.5, + "temperatureApparent": 10.65, + "temperatureDewPoint": 8.17, + "uvIndex": 2, + "visibility": 24553, + "windDirection": 84, + "windGust": 15.97, + "windSpeed": 10.1 + }, + { + "forecastStart": "2026-01-25T20:00:00Z", + "cloudCover": 0.55, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.77, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.84, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.43, + "temperatureApparent": 11.52, + "temperatureDewPoint": 8.51, + "uvIndex": 3, + "visibility": 25278, + "windDirection": 72, + "windGust": 15.97, + "windSpeed": 10.2 + }, + { + "forecastStart": "2026-01-25T21:00:00Z", + "cloudCover": 0.56, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.59, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.16, + "temperatureApparent": 12.23, + "temperatureDewPoint": 8.63, + "uvIndex": 3, + "visibility": 26249, + "windDirection": 48, + "windGust": 15.73, + "windSpeed": 10.31 + }, + { + "forecastStart": "2026-01-25T22:00:00Z", + "cloudCover": 0.53, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.44, + "pressureTrend": "falling", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.61, + "temperatureApparent": 12.72, + "temperatureDewPoint": 8.86, + "uvIndex": 2, + "visibility": 27275, + "windDirection": 12, + "windGust": 15.49, + "windSpeed": 10.61 + }, + { + "forecastStart": "2026-01-25T23:00:00Z", + "cloudCover": 0.5, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.33, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.86, + "temperatureApparent": 12.94, + "temperatureDewPoint": 9.1, + "uvIndex": 1, + "visibility": 28169, + "windDirection": 350, + "windGust": 15.35, + "windSpeed": 11 + }, + { + "forecastStart": "2026-01-26T00:00:00Z", + "cloudCover": 0.47, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.73, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.3, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.87, + "temperatureApparent": 12.82, + "temperatureDewPoint": 9.11, + "uvIndex": 0, + "visibility": 28745, + "windDirection": 347, + "windGust": 14.99, + "windSpeed": 11.17 + }, + { + "forecastStart": "2026-01-26T01:00:00Z", + "cloudCover": 0.46, + "conditionCode": "PartlyCloudy", + "daylight": true, + "humidity": 0.74, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.38, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.56, + "temperatureApparent": 11.66, + "temperatureDewPoint": 9.01, + "uvIndex": 0, + "visibility": 28971, + "windDirection": 2, + "windGust": 14.01, + "windSpeed": 10.93 + }, + { + "forecastStart": "2026-01-26T02:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.76, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.53, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 13.01, + "temperatureApparent": 10.72, + "temperatureDewPoint": 8.88, + "uvIndex": 0, + "visibility": 28991, + "windDirection": 23, + "windGust": 12.67, + "windSpeed": 10.43 + }, + { + "forecastStart": "2026-01-26T03:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.78, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.7, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 12.43, + "temperatureApparent": 10.26, + "temperatureDewPoint": 8.7, + "uvIndex": 0, + "visibility": 28887, + "windDirection": 36, + "windGust": 11.61, + "windSpeed": 9.93 + }, + { + "forecastStart": "2026-01-26T04:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.8, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1023.86, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.91, + "temperatureApparent": 9.86, + "temperatureDewPoint": 8.57, + "uvIndex": 0, + "visibility": 28739, + "windDirection": 45, + "windGust": 11.15, + "windSpeed": 9.48 + }, + { + "forecastStart": "2026-01-26T05:00:00Z", + "cloudCover": 0.45, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.82, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.01, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 11.38, + "temperatureApparent": 9.52, + "temperatureDewPoint": 8.42, + "uvIndex": 0, + "visibility": 28627, + "windDirection": 53, + "windGust": 10.95, + "windSpeed": 9 + }, + { + "forecastStart": "2026-01-26T06:00:00Z", + "cloudCover": 0.46, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.84, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.14, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.91, + "temperatureApparent": 9.23, + "temperatureDewPoint": 8.31, + "uvIndex": 0, + "visibility": 28630, + "windDirection": 59, + "windGust": 10.63, + "windSpeed": 8.56 + }, + { + "forecastStart": "2026-01-26T07:00:00Z", + "cloudCover": 0.46, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.86, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.25, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.48, + "temperatureApparent": 8.98, + "temperatureDewPoint": 8.24, + "uvIndex": 0, + "visibility": 28747, + "windDirection": 66, + "windGust": 9.99, + "windSpeed": 8.09 + }, + { + "forecastStart": "2026-01-26T08:00:00Z", + "cloudCover": 0.45, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.87, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.34, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 10.08, + "temperatureApparent": 8.73, + "temperatureDewPoint": 8.01, + "uvIndex": 0, + "visibility": 28916, + "windDirection": 72, + "windGust": 9.27, + "windSpeed": 7.66 + }, + { + "forecastStart": "2026-01-26T09:00:00Z", + "cloudCover": 0.45, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.38, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.78, + "temperatureApparent": 8.48, + "temperatureDewPoint": 7.89, + "uvIndex": 0, + "visibility": 29117, + "windDirection": 77, + "windGust": 8.83, + "windSpeed": 7.52 + }, + { + "forecastStart": "2026-01-26T10:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.88, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.32, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.64, + "temperatureApparent": 8.22, + "temperatureDewPoint": 7.75, + "uvIndex": 0, + "visibility": 29334, + "windDirection": 75, + "windGust": 8.8, + "windSpeed": 7.84 + }, + { + "forecastStart": "2026-01-26T11:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.89, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.22, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.6, + "temperatureApparent": 7.96, + "temperatureDewPoint": 7.88, + "uvIndex": 0, + "visibility": 29549, + "windDirection": 72, + "windGust": 9.01, + "windSpeed": 8.44 + }, + { + "forecastStart": "2026-01-26T12:00:00Z", + "cloudCover": 0.44, + "conditionCode": "PartlyCloudy", + "daylight": false, + "humidity": 0.89, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.16, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.57, + "temperatureApparent": 7.67, + "temperatureDewPoint": 7.85, + "uvIndex": 0, + "visibility": 29744, + "windDirection": 69, + "windGust": 9.35, + "windSpeed": 9.14 + }, + { + "forecastStart": "2026-01-26T13:00:00Z", + "cloudCover": 1, + "conditionCode": "Cloudy", + "daylight": false, + "humidity": 0.98, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1024.99, + "pressureTrend": "steady", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.09, + "temperatureApparent": 10.32, + "temperatureDewPoint": 8.79, + "uvIndex": 0, + "visibility": 24135, + "windDirection": 344, + "windGust": 3.34, + "windSpeed": 2.57 + }, + { + "forecastStart": "2026-01-26T14:00:00Z", + "cloudCover": 1, + "conditionCode": "Cloudy", + "daylight": false, + "humidity": 0.97, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1025.49, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.15, + "temperatureApparent": 10, + "temperatureDewPoint": 8.7, + "uvIndex": 0, + "visibility": 24135, + "windDirection": 329, + "windGust": 4.36, + "windSpeed": 3.8 + }, + { + "forecastStart": "2026-01-26T15:00:00Z", + "cloudCover": 1, + "conditionCode": "Cloudy", + "daylight": false, + "humidity": 0.94, + "precipitationAmount": 0, + "precipitationIntensity": 0, + "precipitationChance": 0, + "precipitationType": "clear", + "pressure": 1025.91, + "pressureTrend": "rising", + "snowfallIntensity": 0, + "snowfallAmount": 0, + "temperature": 9.38, + "temperatureApparent": 9.92, + "temperatureDewPoint": 8.46, + "uvIndex": 0, + "visibility": 24135, + "windDirection": 327, + "windGust": 4.98, + "windSpeed": 4.64 + } + ] + } + } +} diff --git a/packages/aris-data-source-weatherkit/package.json b/packages/aris-data-source-weatherkit/package.json new file mode 100644 index 0000000..9e711b7 --- /dev/null +++ b/packages/aris-data-source-weatherkit/package.json @@ -0,0 +1,14 @@ +{ + "name": "@aris/data-source-weatherkit", + "version": "0.0.0", + "type": "module", + "main": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "test": "bun test ." + }, + "dependencies": { + "@aris/core": "workspace:*", + "arktype": "^2.1.0" + } +} diff --git a/packages/aris-data-source-weatherkit/scripts/generate-fixtures.ts b/packages/aris-data-source-weatherkit/scripts/generate-fixtures.ts new file mode 100644 index 0000000..042ea94 --- /dev/null +++ b/packages/aris-data-source-weatherkit/scripts/generate-fixtures.ts @@ -0,0 +1,60 @@ +import { DefaultWeatherKitClient } from "../src/weatherkit" + +function loadEnv(): Record { + const content = require("fs").readFileSync(".env", "utf-8") + const env: Record = {} + + for (const line of content.split("\n")) { + const trimmed = line.trim() + if (!trimmed || trimmed.startsWith("#")) continue + + const eqIndex = trimmed.indexOf("=") + if (eqIndex === -1) continue + + const key = trimmed.slice(0, eqIndex) + let value = trimmed.slice(eqIndex + 1) + + if (value.startsWith('"') && value.endsWith('"')) { + value = value.slice(1, -1) + } + + env[key] = value.replace(/\\n/g, "\n") + } + + return env +} + +const env = loadEnv() + +const client = new DefaultWeatherKitClient({ + privateKey: env.WEATHERKIT_PRIVATE_KEY!, + keyId: env.WEATHERKIT_KEY_ID!, + teamId: env.WEATHERKIT_TEAM_ID!, + serviceId: env.WEATHERKIT_SERVICE_ID!, +}) + +const locations = { + sanFrancisco: { lat: 37.7749, lng: -122.4194 }, +} + +async function main() { + console.log("Fetching weather data for San Francisco...") + + const response = await client.fetch({ + lat: locations.sanFrancisco.lat, + lng: locations.sanFrancisco.lng, + }) + + const fixture = { + generatedAt: new Date().toISOString(), + location: locations.sanFrancisco, + response, + } + + const output = JSON.stringify(fixture) + await Bun.write("fixtures/san-francisco.json", output) + + console.log("Fixture written to fixtures/san-francisco.json") +} + +main().catch(console.error) diff --git a/packages/aris-data-source-weatherkit/src/data-source.test.ts b/packages/aris-data-source-weatherkit/src/data-source.test.ts new file mode 100644 index 0000000..cf0a7aa --- /dev/null +++ b/packages/aris-data-source-weatherkit/src/data-source.test.ts @@ -0,0 +1,210 @@ +import type { Context } from "@aris/core" + +import { describe, expect, test } from "bun:test" + +import type { WeatherKitClient, WeatherKitResponse } from "./weatherkit" + +import fixture from "../fixtures/san-francisco.json" +import { WeatherKitDataSource, Units } from "./data-source" +import { WeatherFeedItemType } from "./feed-items" + +const mockCredentials = { + privateKey: "mock", + keyId: "mock", + teamId: "mock", + serviceId: "mock", +} + +const createMockClient = (response: WeatherKitResponse): WeatherKitClient => ({ + fetch: async () => response, +}) + +const createMockContext = (location?: { lat: number; lng: number }): Context => ({ + time: new Date("2026-01-17T00:00:00Z"), + location: location ? { ...location, accuracy: 10 } : undefined, +}) + +describe("WeatherKitDataSource", () => { + test("returns empty array when location is missing", async () => { + const dataSource = new WeatherKitDataSource({ credentials: mockCredentials }) + const items = await dataSource.query(createMockContext()) + + expect(items).toEqual([]) + }) + + test("type is weather-current", () => { + const dataSource = new WeatherKitDataSource({ credentials: mockCredentials }) + + expect(dataSource.type).toBe(WeatherFeedItemType.current) + }) + + test("throws error if neither client nor credentials provided", () => { + expect(() => new WeatherKitDataSource({})).toThrow( + "Either client or credentials must be provided", + ) + }) +}) + +describe("WeatherKitDataSource with fixture", () => { + const response = fixture.response + + test("parses current weather from fixture", () => { + const current = response.currentWeather + + expect(typeof current.conditionCode).toBe("string") + expect(typeof current.temperature).toBe("number") + expect(typeof current.humidity).toBe("number") + expect(current.pressureTrend).toMatch(/^(rising|falling|steady)$/) + }) + + test("parses hourly forecast from fixture", () => { + const hours = response.forecastHourly.hours + + expect(hours.length).toBeGreaterThan(0) + + const firstHour = hours[0]! + expect(firstHour.forecastStart).toBeDefined() + expect(typeof firstHour.temperature).toBe("number") + expect(typeof firstHour.precipitationChance).toBe("number") + }) + + test("parses daily forecast from fixture", () => { + const days = response.forecastDaily.days + + expect(days.length).toBeGreaterThan(0) + + const firstDay = days[0]! + expect(firstDay.forecastStart).toBeDefined() + expect(typeof firstDay.temperatureMax).toBe("number") + expect(typeof firstDay.temperatureMin).toBe("number") + expect(firstDay.sunrise).toBeDefined() + expect(firstDay.sunset).toBeDefined() + }) + + test("hourly limit is respected", () => { + const dataSource = new WeatherKitDataSource({ + credentials: mockCredentials, + hourlyLimit: 6, + }) + + expect(dataSource["hourlyLimit"]).toBe(6) + }) + + test("daily limit is respected", () => { + const dataSource = new WeatherKitDataSource({ + credentials: mockCredentials, + dailyLimit: 3, + }) + + expect(dataSource["dailyLimit"]).toBe(3) + }) + + test("default limits are applied", () => { + const dataSource = new WeatherKitDataSource({ credentials: mockCredentials }) + + expect(dataSource["hourlyLimit"]).toBe(12) + expect(dataSource["dailyLimit"]).toBe(7) + }) +}) + +describe("unit conversion", () => { + test("Units enum has metric and imperial", () => { + expect(Units.metric).toBe("metric") + expect(Units.imperial).toBe("imperial") + }) +}) + +describe("query() with mocked client", () => { + const mockClient = createMockClient(fixture.response as WeatherKitResponse) + + test("transforms API response into feed items", async () => { + const dataSource = new WeatherKitDataSource({ client: mockClient }) + const context = createMockContext({ lat: 37.7749, lng: -122.4194 }) + + const items = await dataSource.query(context) + + expect(items.length).toBeGreaterThan(0) + expect(items.some((i) => i.type === WeatherFeedItemType.current)).toBe(true) + expect(items.some((i) => i.type === WeatherFeedItemType.hourly)).toBe(true) + expect(items.some((i) => i.type === WeatherFeedItemType.daily)).toBe(true) + }) + + test("applies hourly and daily limits", async () => { + const dataSource = new WeatherKitDataSource({ + client: mockClient, + hourlyLimit: 3, + dailyLimit: 2, + }) + const context = createMockContext({ lat: 37.7749, lng: -122.4194 }) + + const items = await dataSource.query(context) + + const hourlyItems = items.filter((i) => i.type === WeatherFeedItemType.hourly) + const dailyItems = items.filter((i) => i.type === WeatherFeedItemType.daily) + + expect(hourlyItems.length).toBe(3) + expect(dailyItems.length).toBe(2) + }) + + test("sets timestamp from context.time", async () => { + const dataSource = new WeatherKitDataSource({ client: mockClient }) + const queryTime = new Date("2026-01-17T12:00:00Z") + const context = createMockContext({ lat: 37.7749, lng: -122.4194 }) + context.time = queryTime + + const items = await dataSource.query(context) + + for (const item of items) { + expect(item.timestamp).toEqual(queryTime) + } + }) + + test("converts temperatures to imperial", async () => { + const dataSource = new WeatherKitDataSource({ client: mockClient }) + const context = createMockContext({ lat: 37.7749, lng: -122.4194 }) + + const metricItems = await dataSource.query(context, { units: Units.metric }) + const imperialItems = await dataSource.query(context, { units: Units.imperial }) + + const metricCurrent = metricItems.find((i) => i.type === WeatherFeedItemType.current) + const imperialCurrent = imperialItems.find((i) => i.type === WeatherFeedItemType.current) + + expect(metricCurrent).toBeDefined() + expect(imperialCurrent).toBeDefined() + + const metricTemp = (metricCurrent!.data as { temperature: number }).temperature + const imperialTemp = (imperialCurrent!.data as { temperature: number }).temperature + + // Verify conversion: F = C * 9/5 + 32 + const expectedImperial = (metricTemp * 9) / 5 + 32 + expect(imperialTemp).toBeCloseTo(expectedImperial, 2) + }) + + test("assigns priority based on weather conditions", async () => { + const dataSource = new WeatherKitDataSource({ client: mockClient }) + const context = createMockContext({ lat: 37.7749, lng: -122.4194 }) + + const items = await dataSource.query(context) + + for (const item of items) { + expect(item.priority).toBeGreaterThanOrEqual(0) + expect(item.priority).toBeLessThanOrEqual(1) + } + + const currentItem = items.find((i) => i.type === WeatherFeedItemType.current) + expect(currentItem).toBeDefined() + // Base priority for current is 0.5, may be adjusted for conditions + expect(currentItem!.priority).toBeGreaterThanOrEqual(0.5) + }) + + test("generates unique IDs for each item", async () => { + const dataSource = new WeatherKitDataSource({ client: mockClient }) + const context = createMockContext({ lat: 37.7749, lng: -122.4194 }) + + const items = await dataSource.query(context) + const ids = items.map((i) => i.id) + const uniqueIds = new Set(ids) + + expect(uniqueIds.size).toBe(ids.length) + }) +}) diff --git a/packages/aris-data-source-weatherkit/src/data-source.ts b/packages/aris-data-source-weatherkit/src/data-source.ts new file mode 100644 index 0000000..634bbed --- /dev/null +++ b/packages/aris-data-source-weatherkit/src/data-source.ts @@ -0,0 +1,306 @@ +import type { Context, DataSource } from "@aris/core" + +import { + WeatherFeedItemType, + type CurrentWeatherFeedItem, + type DailyWeatherFeedItem, + type HourlyWeatherFeedItem, + type WeatherAlertFeedItem, + type WeatherFeedItem, +} from "./feed-items" +import { + ConditionCode, + DefaultWeatherKitClient, + Severity, + type CurrentWeather, + type DailyForecast, + type HourlyForecast, + type WeatherAlert, + type WeatherKitClient, + type WeatherKitCredentials, +} from "./weatherkit" + +export const Units = { + metric: "metric", + imperial: "imperial", +} as const + +export type Units = (typeof Units)[keyof typeof Units] + +export interface WeatherKitDataSourceOptions { + credentials?: WeatherKitCredentials + client?: WeatherKitClient + hourlyLimit?: number + dailyLimit?: number +} + +export interface WeatherKitQueryConfig { + units?: Units +} + +export class WeatherKitDataSource implements DataSource { + private readonly DEFAULT_HOURLY_LIMIT = 12 + private readonly DEFAULT_DAILY_LIMIT = 7 + + readonly type = WeatherFeedItemType.current + private readonly client: WeatherKitClient + private readonly hourlyLimit: number + private readonly dailyLimit: number + + constructor(options: WeatherKitDataSourceOptions) { + if (!options.client && !options.credentials) { + throw new Error("Either client or credentials must be provided") + } + this.client = options.client ?? new DefaultWeatherKitClient(options.credentials!) + this.hourlyLimit = options.hourlyLimit ?? this.DEFAULT_HOURLY_LIMIT + this.dailyLimit = options.dailyLimit ?? this.DEFAULT_DAILY_LIMIT + } + + async query(context: Context, config: WeatherKitQueryConfig = {}): Promise { + if (!context.location) { + return [] + } + + const units = config.units ?? Units.metric + const timestamp = context.time + + const response = await this.client.fetch({ + lat: context.location.lat, + lng: context.location.lng, + }) + + const items: WeatherFeedItem[] = [] + + if (response.currentWeather) { + items.push(createCurrentWeatherFeedItem(response.currentWeather, timestamp, units)) + } + + if (response.forecastHourly?.hours) { + const hours = response.forecastHourly.hours.slice(0, this.hourlyLimit) + for (let i = 0; i < hours.length; i++) { + const hour = hours[i] + if (hour) { + items.push(createHourlyWeatherFeedItem(hour, i, timestamp, units)) + } + } + } + + if (response.forecastDaily?.days) { + const days = response.forecastDaily.days.slice(0, this.dailyLimit) + for (let i = 0; i < days.length; i++) { + const day = days[i] + if (day) { + items.push(createDailyWeatherFeedItem(day, i, timestamp, units)) + } + } + } + + if (response.weatherAlerts?.alerts) { + for (const alert of response.weatherAlerts.alerts) { + items.push(createWeatherAlertFeedItem(alert, timestamp)) + } + } + + return items + } +} + +const BASE_PRIORITY = { + current: 0.5, + hourly: 0.3, + daily: 0.2, + alert: 0.7, +} as const + +const SEVERE_CONDITIONS = new Set([ + ConditionCode.SevereThunderstorm, + ConditionCode.Hurricane, + ConditionCode.Tornado, + ConditionCode.TropicalStorm, + ConditionCode.Blizzard, + ConditionCode.FreezingRain, + ConditionCode.Hail, + ConditionCode.Frigid, + ConditionCode.Hot, +]) + +const MODERATE_CONDITIONS = new Set([ + ConditionCode.Thunderstorm, + ConditionCode.IsolatedThunderstorms, + ConditionCode.ScatteredThunderstorms, + ConditionCode.HeavyRain, + ConditionCode.HeavySnow, + ConditionCode.FreezingDrizzle, + ConditionCode.BlowingSnow, +]) + +function adjustPriorityForCondition(basePriority: number, conditionCode: ConditionCode): number { + if (SEVERE_CONDITIONS.has(conditionCode)) { + return Math.min(1, basePriority + 0.3) + } + if (MODERATE_CONDITIONS.has(conditionCode)) { + return Math.min(1, basePriority + 0.15) + } + return basePriority +} + +function adjustPriorityForAlertSeverity(severity: Severity): number { + switch (severity) { + case Severity.Extreme: + return 1 + case Severity.Severe: + return 0.9 + case Severity.Moderate: + return 0.75 + case Severity.Minor: + return BASE_PRIORITY.alert + } +} + +function convertTemperature(celsius: number, units: Units): number { + if (units === Units.imperial) { + return (celsius * 9) / 5 + 32 + } + return celsius +} + +function convertSpeed(kmh: number, units: Units): number { + if (units === Units.imperial) { + return kmh * 0.621371 + } + return kmh +} + +function convertDistance(km: number, units: Units): number { + if (units === Units.imperial) { + return km * 0.621371 + } + return km +} + +function convertPrecipitation(mm: number, units: Units): number { + if (units === Units.imperial) { + return mm * 0.0393701 + } + return mm +} + +function convertPressure(mb: number, units: Units): number { + if (units === Units.imperial) { + return mb * 0.02953 + } + return mb +} + +function createCurrentWeatherFeedItem( + current: CurrentWeather, + timestamp: Date, + units: Units, +): CurrentWeatherFeedItem { + const priority = adjustPriorityForCondition(BASE_PRIORITY.current, current.conditionCode) + + return { + id: `weather-current-${timestamp.getTime()}`, + type: WeatherFeedItemType.current, + priority, + timestamp, + data: { + conditionCode: current.conditionCode, + daylight: current.daylight, + humidity: current.humidity, + precipitationIntensity: convertPrecipitation(current.precipitationIntensity, units), + pressure: convertPressure(current.pressure, units), + pressureTrend: current.pressureTrend, + temperature: convertTemperature(current.temperature, units), + temperatureApparent: convertTemperature(current.temperatureApparent, units), + uvIndex: current.uvIndex, + visibility: convertDistance(current.visibility, units), + windDirection: current.windDirection, + windGust: convertSpeed(current.windGust, units), + windSpeed: convertSpeed(current.windSpeed, units), + }, + } +} + +function createHourlyWeatherFeedItem( + hourly: HourlyForecast, + index: number, + timestamp: Date, + units: Units, +): HourlyWeatherFeedItem { + const priority = adjustPriorityForCondition(BASE_PRIORITY.hourly, hourly.conditionCode) + + return { + id: `weather-hourly-${timestamp.getTime()}-${index}`, + type: WeatherFeedItemType.hourly, + priority, + timestamp, + data: { + forecastTime: new Date(hourly.forecastStart), + conditionCode: hourly.conditionCode, + daylight: hourly.daylight, + humidity: hourly.humidity, + precipitationAmount: convertPrecipitation(hourly.precipitationAmount, units), + precipitationChance: hourly.precipitationChance, + precipitationType: hourly.precipitationType, + temperature: convertTemperature(hourly.temperature, units), + temperatureApparent: convertTemperature(hourly.temperatureApparent, units), + uvIndex: hourly.uvIndex, + windDirection: hourly.windDirection, + windGust: convertSpeed(hourly.windGust, units), + windSpeed: convertSpeed(hourly.windSpeed, units), + }, + } +} + +function createDailyWeatherFeedItem( + daily: DailyForecast, + index: number, + timestamp: Date, + units: Units, +): DailyWeatherFeedItem { + const priority = adjustPriorityForCondition(BASE_PRIORITY.daily, daily.conditionCode) + + return { + id: `weather-daily-${timestamp.getTime()}-${index}`, + type: WeatherFeedItemType.daily, + priority, + timestamp, + data: { + forecastDate: new Date(daily.forecastStart), + conditionCode: daily.conditionCode, + maxUvIndex: daily.maxUvIndex, + precipitationAmount: convertPrecipitation(daily.precipitationAmount, units), + precipitationChance: daily.precipitationChance, + precipitationType: daily.precipitationType, + snowfallAmount: convertPrecipitation(daily.snowfallAmount, units), + sunrise: new Date(daily.sunrise), + sunset: new Date(daily.sunset), + temperatureMax: convertTemperature(daily.temperatureMax, units), + temperatureMin: convertTemperature(daily.temperatureMin, units), + }, + } +} + +function createWeatherAlertFeedItem(alert: WeatherAlert, timestamp: Date): WeatherAlertFeedItem { + const priority = adjustPriorityForAlertSeverity(alert.severity) + + return { + id: `weather-alert-${alert.id}`, + type: WeatherFeedItemType.alert, + priority, + timestamp, + data: { + alertId: alert.id, + areaName: alert.areaName, + certainty: alert.certainty, + description: alert.description, + detailsUrl: alert.detailsUrl, + effectiveTime: new Date(alert.effectiveTime), + expireTime: new Date(alert.expireTime), + severity: alert.severity, + source: alert.source, + urgency: alert.urgency, + }, + } +} diff --git a/packages/aris-data-source-weatherkit/src/feed-items.ts b/packages/aris-data-source-weatherkit/src/feed-items.ts new file mode 100644 index 0000000..0005846 --- /dev/null +++ b/packages/aris-data-source-weatherkit/src/feed-items.ts @@ -0,0 +1,97 @@ +import type { FeedItem } from "@aris/core" + +import type { Certainty, ConditionCode, PrecipitationType, Severity, Urgency } from "./weatherkit" + +export const WeatherFeedItemType = { + current: "weather-current", + hourly: "weather-hourly", + daily: "weather-daily", + alert: "weather-alert", +} as const + +export type WeatherFeedItemType = (typeof WeatherFeedItemType)[keyof typeof WeatherFeedItemType] + +export type CurrentWeatherData = { + conditionCode: ConditionCode + daylight: boolean + humidity: number + precipitationIntensity: number + pressure: number + pressureTrend: "rising" | "falling" | "steady" + temperature: number + temperatureApparent: number + uvIndex: number + visibility: number + windDirection: number + windGust: number + windSpeed: number +} + +export interface CurrentWeatherFeedItem extends FeedItem< + typeof WeatherFeedItemType.current, + CurrentWeatherData +> {} + +export type HourlyWeatherData = { + forecastTime: Date + conditionCode: ConditionCode + daylight: boolean + humidity: number + precipitationAmount: number + precipitationChance: number + precipitationType: PrecipitationType + temperature: number + temperatureApparent: number + uvIndex: number + windDirection: number + windGust: number + windSpeed: number +} + +export interface HourlyWeatherFeedItem extends FeedItem< + typeof WeatherFeedItemType.hourly, + HourlyWeatherData +> {} + +export type DailyWeatherData = { + forecastDate: Date + conditionCode: ConditionCode + maxUvIndex: number + precipitationAmount: number + precipitationChance: number + precipitationType: PrecipitationType + snowfallAmount: number + sunrise: Date + sunset: Date + temperatureMax: number + temperatureMin: number +} + +export interface DailyWeatherFeedItem extends FeedItem< + typeof WeatherFeedItemType.daily, + DailyWeatherData +> {} + +export type WeatherAlertData = { + alertId: string + areaName: string + certainty: Certainty + description: string + detailsUrl: string + effectiveTime: Date + expireTime: Date + severity: Severity + source: string + urgency: Urgency +} + +export interface WeatherAlertFeedItem extends FeedItem< + typeof WeatherFeedItemType.alert, + WeatherAlertData +> {} + +export type WeatherFeedItem = + | CurrentWeatherFeedItem + | HourlyWeatherFeedItem + | DailyWeatherFeedItem + | WeatherAlertFeedItem diff --git a/packages/aris-data-source-weatherkit/src/index.ts b/packages/aris-data-source-weatherkit/src/index.ts new file mode 100644 index 0000000..d818113 --- /dev/null +++ b/packages/aris-data-source-weatherkit/src/index.ts @@ -0,0 +1,38 @@ +export { + WeatherKitDataSource, + Units, + type Units as UnitsType, + type WeatherKitDataSourceOptions, + type WeatherKitQueryConfig, +} from "./data-source" + +export { + WeatherFeedItemType, + type WeatherFeedItemType as WeatherFeedItemTypeType, + type CurrentWeatherData, + type CurrentWeatherFeedItem, + type DailyWeatherData, + type DailyWeatherFeedItem, + type HourlyWeatherData, + type HourlyWeatherFeedItem, + type WeatherAlertData, + type WeatherAlertFeedItem, + type WeatherFeedItem, +} from "./feed-items" + +export { + Severity, + Urgency, + Certainty, + PrecipitationType, + ConditionCode, + DefaultWeatherKitClient, + type Severity as SeverityType, + type Urgency as UrgencyType, + type Certainty as CertaintyType, + type PrecipitationType as PrecipitationTypeType, + type ConditionCode as ConditionCodeType, + type WeatherKitCredentials, + type WeatherKitClient, + type WeatherKitQueryOptions, +} from "./weatherkit" diff --git a/packages/aris-data-source-weatherkit/src/weatherkit.ts b/packages/aris-data-source-weatherkit/src/weatherkit.ts new file mode 100644 index 0000000..455e465 --- /dev/null +++ b/packages/aris-data-source-weatherkit/src/weatherkit.ts @@ -0,0 +1,367 @@ +// WeatherKit REST API client and response types +// https://developer.apple.com/documentation/weatherkitrestapi + +import { type } from "arktype" + +export interface WeatherKitCredentials { + privateKey: string + keyId: string + teamId: string + serviceId: string +} + +export interface WeatherKitQueryOptions { + lat: number + lng: number + language?: string + timezone?: string +} + +export interface WeatherKitClient { + fetch(query: WeatherKitQueryOptions): Promise +} + +export class DefaultWeatherKitClient implements WeatherKitClient { + private readonly credentials: WeatherKitCredentials + + constructor(credentials: WeatherKitCredentials) { + this.credentials = credentials + } + + async fetch(query: WeatherKitQueryOptions): Promise { + const token = await generateJwt(this.credentials) + + const dataSets = ["currentWeather", "forecastHourly", "forecastDaily", "weatherAlerts"].join( + ",", + ) + + const url = new URL( + `${WEATHERKIT_API_BASE}/weather/${query.language ?? "en"}/${query.lat}/${query.lng}`, + ) + url.searchParams.set("dataSets", dataSets) + if (query.timezone) { + url.searchParams.set("timezone", query.timezone) + } + + const response = await fetch(url.toString(), { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + + if (!response.ok) { + const body = await response.text() + throw new Error(`WeatherKit API error: ${response.status} ${response.statusText}: ${body}`) + } + + const json = await response.json() + const result = weatherKitResponseSchema(json) + + if (result instanceof type.errors) { + throw new Error(`WeatherKit API response validation failed: ${result.summary}`) + } + + return result + } +} + +export const Severity = { + Minor: "minor", + Moderate: "moderate", + Severe: "severe", + Extreme: "extreme", +} as const + +export type Severity = (typeof Severity)[keyof typeof Severity] + +export const Urgency = { + Immediate: "immediate", + Expected: "expected", + Future: "future", + Past: "past", + Unknown: "unknown", +} as const + +export type Urgency = (typeof Urgency)[keyof typeof Urgency] + +export const Certainty = { + Observed: "observed", + Likely: "likely", + Possible: "possible", + Unlikely: "unlikely", + Unknown: "unknown", +} as const + +export type Certainty = (typeof Certainty)[keyof typeof Certainty] + +export const PrecipitationType = { + Clear: "clear", + Precipitation: "precipitation", + Rain: "rain", + Snow: "snow", + Sleet: "sleet", + Hail: "hail", + Mixed: "mixed", +} as const + +export type PrecipitationType = (typeof PrecipitationType)[keyof typeof PrecipitationType] + +export const ConditionCode = { + Clear: "Clear", + Cloudy: "Cloudy", + Dust: "Dust", + Fog: "Fog", + Haze: "Haze", + MostlyClear: "MostlyClear", + MostlyCloudy: "MostlyCloudy", + PartlyCloudy: "PartlyCloudy", + ScatteredThunderstorms: "ScatteredThunderstorms", + Smoke: "Smoke", + Breezy: "Breezy", + Windy: "Windy", + Drizzle: "Drizzle", + HeavyRain: "HeavyRain", + Rain: "Rain", + Showers: "Showers", + Flurries: "Flurries", + HeavySnow: "HeavySnow", + MixedRainAndSleet: "MixedRainAndSleet", + MixedRainAndSnow: "MixedRainAndSnow", + MixedRainfall: "MixedRainfall", + MixedSnowAndSleet: "MixedSnowAndSleet", + ScatteredShowers: "ScatteredShowers", + ScatteredSnowShowers: "ScatteredSnowShowers", + Sleet: "Sleet", + Snow: "Snow", + SnowShowers: "SnowShowers", + Blizzard: "Blizzard", + BlowingSnow: "BlowingSnow", + FreezingDrizzle: "FreezingDrizzle", + FreezingRain: "FreezingRain", + Frigid: "Frigid", + Hail: "Hail", + Hot: "Hot", + Hurricane: "Hurricane", + IsolatedThunderstorms: "IsolatedThunderstorms", + SevereThunderstorm: "SevereThunderstorm", + Thunderstorm: "Thunderstorm", + Tornado: "Tornado", + TropicalStorm: "TropicalStorm", +} as const + +export type ConditionCode = (typeof ConditionCode)[keyof typeof ConditionCode] + +const WEATHERKIT_API_BASE = "https://weatherkit.apple.com/api/v1" + +const severitySchema = type.enumerated( + Severity.Minor, + Severity.Moderate, + Severity.Severe, + Severity.Extreme, +) + +const urgencySchema = type.enumerated( + Urgency.Immediate, + Urgency.Expected, + Urgency.Future, + Urgency.Past, + Urgency.Unknown, +) + +const certaintySchema = type.enumerated( + Certainty.Observed, + Certainty.Likely, + Certainty.Possible, + Certainty.Unlikely, + Certainty.Unknown, +) + +const precipitationTypeSchema = type.enumerated( + PrecipitationType.Clear, + PrecipitationType.Precipitation, + PrecipitationType.Rain, + PrecipitationType.Snow, + PrecipitationType.Sleet, + PrecipitationType.Hail, + PrecipitationType.Mixed, +) + +const conditionCodeSchema = type.enumerated(...Object.values(ConditionCode)) + +const pressureTrendSchema = type.enumerated("rising", "falling", "steady") + +const currentWeatherSchema = type({ + asOf: "string", + conditionCode: conditionCodeSchema, + daylight: "boolean", + humidity: "number", + precipitationIntensity: "number", + pressure: "number", + pressureTrend: pressureTrendSchema, + temperature: "number", + temperatureApparent: "number", + temperatureDewPoint: "number", + uvIndex: "number", + visibility: "number", + windDirection: "number", + windGust: "number", + windSpeed: "number", +}) + +export type CurrentWeather = typeof currentWeatherSchema.infer + +const hourlyForecastSchema = type({ + forecastStart: "string", + conditionCode: conditionCodeSchema, + daylight: "boolean", + humidity: "number", + precipitationAmount: "number", + precipitationChance: "number", + precipitationType: precipitationTypeSchema, + pressure: "number", + snowfallIntensity: "number", + temperature: "number", + temperatureApparent: "number", + temperatureDewPoint: "number", + uvIndex: "number", + visibility: "number", + windDirection: "number", + windGust: "number", + windSpeed: "number", +}) + +export type HourlyForecast = typeof hourlyForecastSchema.infer + +const dayWeatherConditionsSchema = type({ + conditionCode: conditionCodeSchema, + humidity: "number", + precipitationAmount: "number", + precipitationChance: "number", + precipitationType: precipitationTypeSchema, + snowfallAmount: "number", + temperatureMax: "number", + temperatureMin: "number", + windDirection: "number", + "windGust?": "number", + windSpeed: "number", +}) + +export type DayWeatherConditions = typeof dayWeatherConditionsSchema.infer + +const dailyForecastSchema = type({ + forecastStart: "string", + forecastEnd: "string", + conditionCode: conditionCodeSchema, + maxUvIndex: "number", + moonPhase: "string", + "moonrise?": "string", + "moonset?": "string", + precipitationAmount: "number", + precipitationChance: "number", + precipitationType: precipitationTypeSchema, + snowfallAmount: "number", + sunrise: "string", + sunriseCivil: "string", + sunriseNautical: "string", + sunriseAstronomical: "string", + sunset: "string", + sunsetCivil: "string", + sunsetNautical: "string", + sunsetAstronomical: "string", + temperatureMax: "number", + temperatureMin: "number", + "daytimeForecast?": dayWeatherConditionsSchema, + "overnightForecast?": dayWeatherConditionsSchema, +}) + +export type DailyForecast = typeof dailyForecastSchema.infer + +const weatherAlertSchema = type({ + id: "string", + areaId: "string", + areaName: "string", + certainty: certaintySchema, + countryCode: "string", + description: "string", + detailsUrl: "string", + effectiveTime: "string", + expireTime: "string", + issuedTime: "string", + responses: "string[]", + severity: severitySchema, + source: "string", + urgency: urgencySchema, +}) + +export type WeatherAlert = typeof weatherAlertSchema.infer + +const weatherKitResponseSchema = type({ + "currentWeather?": currentWeatherSchema, + "forecastHourly?": type({ + hours: hourlyForecastSchema.array(), + }), + "forecastDaily?": type({ + days: dailyForecastSchema.array(), + }), + "weatherAlerts?": type({ + alerts: weatherAlertSchema.array(), + }), +}) + +export type WeatherKitResponse = typeof weatherKitResponseSchema.infer + +async function generateJwt(credentials: WeatherKitCredentials): Promise { + const header = { + alg: "ES256", + kid: credentials.keyId, + id: `${credentials.teamId}.${credentials.serviceId}`, + } + + const now = Math.floor(Date.now() / 1000) + const payload = { + iss: credentials.teamId, + iat: now, + exp: now + 3600, + sub: credentials.serviceId, + } + + const encoder = new TextEncoder() + const headerB64 = btoa(JSON.stringify(header)) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, "") + const payloadB64 = btoa(JSON.stringify(payload)) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, "") + + const signingInput = `${headerB64}.${payloadB64}` + + const pemContents = credentials.privateKey + .replace(/-----BEGIN PRIVATE KEY-----/, "") + .replace(/-----END PRIVATE KEY-----/, "") + .replace(/\s/g, "") + + const binaryKey = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0)) + + const cryptoKey = await crypto.subtle.importKey( + "pkcs8", + binaryKey, + { name: "ECDSA", namedCurve: "P-256" }, + false, + ["sign"], + ) + + const signature = await crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-256" }, + cryptoKey, + encoder.encode(signingInput), + ) + + const signatureB64 = btoa(String.fromCharCode(...new Uint8Array(signature))) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, "") + + return `${signingInput}.${signatureB64}` +}