{"id":19224371,"url":"https://github.com/snowplow/scala-weather","last_synced_at":"2025-04-21T00:30:28.661Z","repository":{"id":28039519,"uuid":"31535192","full_name":"snowplow/scala-weather","owner":"snowplow","description":"High-performance Scala library for looking up the weather","archived":false,"fork":false,"pushed_at":"2022-03-09T12:24:12.000Z","size":1563,"stargazers_count":44,"open_issues_count":4,"forks_count":13,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-04-01T07:11:03.759Z","etag":null,"topics":["api-wrapper","openweathermap","scala","weather"],"latest_commit_sha":null,"homepage":"https://snowplow.github.io/scala-weather/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snowplow.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-2.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-02T10:29:23.000Z","updated_at":"2025-02-21T20:26:44.000Z","dependencies_parsed_at":"2022-09-11T04:20:48.857Z","dependency_job_id":null,"html_url":"https://github.com/snowplow/scala-weather","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snowplow%2Fscala-weather","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snowplow%2Fscala-weather/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snowplow%2Fscala-weather/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snowplow%2Fscala-weather/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snowplow","download_url":"https://codeload.github.com/snowplow/scala-weather/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249979501,"owners_count":21355247,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-wrapper","openweathermap","scala","weather"],"created_at":"2024-11-09T15:11:30.250Z","updated_at":"2025-04-21T00:30:28.431Z","avatar_url":"https://github.com/snowplow.png","language":"Scala","funding_links":[],"categories":["API\u0026客户端"],"sub_categories":["文件同步"],"readme":"# Scala Weather\n\n[![Build Status][ci-image]][ci]\n[![Maven Central][release-image]][releases]\n[![Coverage Status][coveralls-image]][coveralls]\n[![License][license-image]][license]\n\n## Overview\n\nHigh-performance, asynchronous and cache-aware Scala library for looking up the weather.\n\nUsed in **[Snowplow][snowplow-repo]** to power the **[Weather Enrichment][weather-enrichment]** for incoming events.\n\n## Introduction\n\nScala Weather contains APIs to 2 weather providers: **[OpenWeatherMap][openweathermap]** and **[Dark Sky][darksky]**.\nIt allows you to fetch the current weather, historical weather and weather forecasts for any city (OWM only) or geo coordinates.\n\nWe provide caching and basic clients for both providers - `OwmClient` and `OwmCacheClient` for OpenWeatherMap, `DarkSkyClient` and `DarkSkyCacheClient` for Dark Sky.\n\n## Installation\n\nThe latest version of Scala Weather is 2.0.0, which is cross-built against Scala 2.12 \u0026 2.13.\n\nIf you're using SBT, add the following lines to your build file:\n\n```scala\nlibraryDependencies += \"com.snowplowanalytics\" %% \"scala-weather\" % \"2.0.0\"\n```\n\n## Guide\n\n**Note:** All of the clients take `F` as a type parameter. It can be any type that has an instance\nof `cats.effect.Sync`, here we use `cats.effect.IO`. We also provide instances for\n`cats.Eval` and `cats.Id` in cases side-effects are needed (e.g. Spark or Beam)\n\n### OpenWeatherMap\n\nFirst **[sign up][owm-signup]** to OpenWeatherMap to get your API key.\n\nUnfortunately, with the free plan you can only perform current weather and forecast lookups; for historical data access you need to subscribe to the **[history plan][history-plan]**. If you use the free plan all `historyBy...` methods will return failures.\n\n#### Usage\n\nOnce you have your API key, you can create a client:\n\n```scala\nimport scala.concurrent.duration._\nimport com.snowplowanalytics.weather.providers.openweather.CreateOWM\nimport cats.{Eval, Id}\nimport cats.effect.IO\nval client = CreateOWM[IO].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds, ssl = true)\n// using Eval and Id\nval evalClient = CreateOWM[Eval].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds, ssl = true)\nval idClient = CreateOWM[Id].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds, ssl = true)\n```\n\nOpenWeatherMap provides several hosts for API with various benefits, which you can pass as the first argument:\n\n+ `api.openweathermap.org` - free access, recommended\n+ `history.openweathermap.org` - paid, history only\n+ `pro.openweathermap.org` - paid, faster, SSL-enabled\n\nBoth the caching and normal clients offer the same set of public methods:\n\n+ `forecastById`\n+ `forecastByName`\n+ `forecastByCoords`\n+ `currentById`\n+ `currentByName`\n+ `currentByCoords`\n+ `historyById`\n+ `historyByName`\n+ `historyByCoords`\n\nThese methods were designed to follow OpenWeatherMap's own API calls as closely as possible. All of these calls receive similar arguments to those described in **[OpenWeatherMap API documentation][owm-api-docs]**. For example, to receive a response equivalent to this API call: ``api.openweathermap.org/data/2.5/weather?lat=35\u0026lon=139\u0026appid=YOURKEY``, run the following code:\n\n```scala\nimport com.snowplowanalytics.weather.errors.WeatherError\nimport com.snowplowanalytics.weather.providers.openweather.responses.Current\nval weatherInLondon: IO[Either[WeatherError, Current]] = client.currentByCoords(35.0f, 139.0f)\n// using Eval and Id\nval evalWeatherInLondon: Eval[Either[WeatherError, Current]] = evalClient.currentByCoords(35.0f, 139.0f)\nval idWeatherInLondon: Either[WeatherError, Current] = idClient.currentByCoords(35.0f, 139.0f)\n```\n\nNotice that all temperature fields are in Kelvin, which is the OpenWeatherMap default (OWM only supports unit preference for the current weather).\n\nScala Weather doesn't try to validate your arguments (except of course their types), so invalid calls like this one:\n\n```scala\n// Count is supposed to be positive\nval forecast: IO[Either[WeatherError, Current]] = client.forecastById(3070325, cnt=-1)\n```\n\nwill still be executed and OpenWeatherMap will decide how to handle it (in this case, it will ignore negative count).\n\nThe caching client is created like this:\n```scala\nval cachingClient = CreateOWM[IO].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds, ssl = true, cacheSize = 5000, geoPrecision = 2)\n```\nMore on `cacheSize` and `geoPrecision` below.\n\n### Dark Sky\n\nSign up **[here][darkskydev]** to receive the API key. Dark Sky currently allows for 1000 free requests per day.\n\n#### Usage\n\nSimilar to OpenWeatherMap, to create a basic client you can use the factories in the `DarkSky` object:\n```scala\nimport com.snowplowanalytics.weather.providers.darksky.DarkSky\nimport cats.{Eval, Id}\nimport cats.effect.IO\n\nval client = CreateOWM[IO].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds)\n// using Eval and Id\nval evalClient = CreateDarkSky[Eval].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds)\nval idClient = CreateDarkSky[Id].create(\n  \"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds)\n```\n\nDark Sky API is much simpler than OWM, it consists only of two functions, namely `forecast` and `timeMachine`\n\n- `forecast` returns the current weather and the forecast for next week\n- `timeMachine` returns the observed or forecast weather for the specified date in the past or the future\n\nExample:\n\n```scala\nimport java.time.ZonedDateTime\nimport com.snowplowanalytics.weather.errors.WeatherError\nimport com.snowplowanalytics.weather.providers.darksky.responses.DarkSkyResponse\n// Fetches weather a year ago in New York\nval response: IO[Either[WeatherError, DarkSkyResponse]] =\n  client.timeMachine(40.71f, 74.0f, ZonedDateTime.now().minusYears(1))\n```\n\nUnlike OpenWeatherMap, Dark Sky does not provide geocoding features,\nmeaning you must know the latitude and longitude of the location.\n\n## Understanding the cache\n\n### General information\n\nScala Weather provides a cache as part of the `weather.providers.openweather.OwmCacheClient` or `weather.providers.darksky.DarkSkyCacheClient`.\nIt uses an **[LRU cache][lru]** under the hood and only works for historical lookups. OpenWeatherMap restricts the number of history lookups you can make on the paid plans, so this cache helps to minimize requests, especially when run from a \"big data\" frameworks.\n\nNote that the results of common methods like `historyById`, `currentByCoords` etc are not cached.\nTo employ the cache, you need to use:\n\n - for OWM `cachingHistoryByCoords`\n - for Dark Sky `cachingTimeMachine`\n\nThe following client factory arguments help to tune the cache:\n\n* `cacheSize` determines how many daily weather reports for a location can be stored in the cache before entries start getting evicted\n* `geoPrecision` determines how precise your cache will be from geospatial perspective\n\n### Understanding the `geoPrecision`\n\nThis essentially rounds the decimal places part of the geo coordinate to the specified part of 1. Some example settings:\n\n* Setting to 1 will round both 32.05 and 32.4 to 32.0 (so 1/1)\n* Setting to 2 will round 32.4 to 32.5, and 30.1 to 30.0 (so, 1/2)\n* Setting to 5 will round 42.11 to 42.2 (so, 1/5)\n\nIn the worst precision case (`geoPrecision == 1`), our geo-locations for the weather will be up to ~60km out. But you need to note that the primary sources of weather inaccuracies are not usually distance, but things like urban/suburbian area, or rapid extreme weather changes, or the distance to the closest weather station (hundreds kilometers in some rare cases).\n\nSo, you can consider 1 as a good default value; it's strongly discouraged to set it higher than 10.\n\n### How the cache works\n\n`OwmCacheClient` and `DarkSkyCacheClient`'s internal cache stores responses in a map, which key is\ncomputed roughly as:\n\n`round(latitude), round(longitude), beginningOfDay`\n\nAfter the first request, it will try to fetch information for this exact place (round(latitude), round(longitude)) for the given day.\nThe OWM cache value usually consists of several (8-24) `Weather` objects, each with its own timestamps.\n\n`cachingHistoryByCoords` in the OWM client will return the closest weather for the specified timestamp and leave the others in the cache.\nFor example, the following code will make only one request to OpenWeatherMap, but return 3 distinct results:\n\n`cachingTimeMachine` in the Dark Sky client will return the whole `DarkSkyResponse` for the specified day.\nThe field `currently` will be omitted, so the user must rely on the `hourly` or `daily` fields.\n\nThe return type of both caching clients creation is wrapped in the effect type, as\nthe creation of the underlying cache allocates mutable state.\n\n```scala\nimport com.snowplowanalytics.weather.providers.openweather.OpenWeatherMap\nimport cats.effect.IO\n\nval action = for {\n  client \u003c- CreateOWM[IO].create(\"history.openweathermap.org\", \"YOUR_KEY\", timeout = 1.seconds, ssl = true, cacheSize = 10, geoPrecision = 1)\n  response1 \u003c- client.cachingHistoryByCoords(10.4f, 32.1f, 1514765952)   // Jan 1 12:19:12 2018.\n  response2 \u003c- client.cachingHistoryByCoords(10.1f, 32.312f, 1514821267) // Jan 1 15:41:07 2018. From cache\n  response3 \u003c- client.cachingHistoryByCoords(10.2f, 32.4f, 1514776320)   // Jan 1 03:12:00 2018. From cache\n} yield (response1, response2, response3)\n\naction.unsafeRunSync()\n```\n\n\n## Copyright and license\n\nScala Weather is copyright 2015-2022 Snowplow Analytics Ltd.\n\nLicensed under the **[Apache License, Version 2.0][license]**  (the \"License\");\nyou may not use this software except in compliance with the License.\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n[openweathermap]: http://openweathermap.org/\n[owm-api-docs]: http://openweathermap.org/api\n[darksky]: https://darksky.net\n[darkskydev]: https://darksky.net/dev\n[lru]: https://en.wikipedia.org/wiki/Cache_algorithms#LRU\n[history-plan]: https://openweathermap.org/price\n[owm-signup]: https://home.openweathermap.org/users/sign_up\n\n[snowplow]: https://snowplowanalytics.com\n[snowplow-repo]: https://github.com/snowplow/snowplow\n[weather-enrichment]: https://github.com/snowplow/snowplow/wiki/Weather-enrichment\n\n[coveralls]: https://coveralls.io/github/snowplow/scala-weather?branch=master\n[coveralls-image]: https://coveralls.io/repos/github/snowplow/scala-weather/badge.svg?branch=master\n\n[ci]: https://github.com/snowplow/scala-weather/actions?query=workflow%3ACI\n[ci-image]: https://github.com/snowplow/scala-weather/workflows/CI/badge.svg\n\n[releases]: https://maven-badges.herokuapp.com/maven-central/com.snowplowanalytics/scala-weather_2.12\n[release-image]: https://img.shields.io/maven-central/v/com.snowplowanalytics/scala-weather_2.12.svg\n\n[license-image]: http://img.shields.io/badge/license-Apache--2-blue.svg?style=flat\n[license]: http://www.apache.org/licenses/LICENSE-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnowplow%2Fscala-weather","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnowplow%2Fscala-weather","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnowplow%2Fscala-weather/lists"}