OpenWeatherMap is an online service that provides weather data, including current weather data, forecasts, and historical data to the developers of web services and mobile applications.
For data sources, it utilizes meteorological broadcast services, raw data from airport weather stations, raw data from radar stations, and raw data from other official weather stations.
Coverage:
In order to make requests you need to register at https://openweathermap.org and obtain an API. Save the key in a file called own.key . Then run
make run
# or: stack exec test-owmimport qualified Network.Owm as Owm
import Network.Owm (CityName(..), CityId(..), Coords(..), CountryCode, ZipCode(..), Count(..))
import qualified Network.Owm.Forecast as Forecast
import qualified Network.Owm.ForecastDaily as ForecastDaily
import qualified Network.Owm.Weather as Weather
key <- Owm.Key <$> readFile fCurrent weather is obtained by calling one of the functions in Network.Owm.Weather,
weather <- Weather.fromCityId key Owm.Metric Owm.EN (CityId 2172797)
print weatherAll functions require the arguments Units and Lang. For example, Units is defined as
data Units = Metric | Standard | Imperial -- src/Network/Owm/Owm.hsSimilarly, Lang is one of the supported ISO codes like Lang.EN, Lang.FR, Lang.ES.
For Weather (current weather), Forecast and ForecastDaily there are four functions each. The four ways to get the weather are
-- by name
Weather.fromCityName key Owm.Metric Owm.EN (CityName "Altendorf" "CH")
-- by city id
Weather.fromCityId key Owm.Metric Owm.EN (CityId 2172797)
-- by geo coordinates (latitude/longitude)
Weather.fromCoords key Owm.Metric Owm.EN (Owm.Coords 47.37643 8.54782)
-- by zip code
Weather.fromZipCode key Owm.Metric Owm.EN (ZipCode 8001 "CH")CityName and ZipCode allow an optional country code. To specify the default country (USA) code use
ZipCode 60606 DefaultCountryForecast and ForecastDaily have similar four functions, with an extra parameter Count. For example, the 3 day forcast for the north pole, in Swedish, is obtained like this:
w<-ForecastDaily.fromCoords key Owm.Metric Owm.SE (Owm.Coords 90.0 0.0) (Count 3)w' = fromJust w -- import Data.Maybe (fromJust)
forecastDailyCod w' -- check return code, should be 200
ForecastDaily.listEltTemp <$> forecastDailyList w'The result is something like
[Temp {tempMax = -17.8, tempDay = -17.94, tempNight = -20.45, tempMin = -20.45,
tempMorn = -17.8, tempEve = -18.76},
Temp {tempMax = -21.36, tempDay = -22.46, tempNight = -21.36, tempMin = -22.46,
tempMorn = -22.46, tempEve = -22.4},
Temp {tempMax = -17.7, tempDay = -20.14, tempNight = -17.7, tempMin = -21.36,
tempMorn = -21.36, tempEve = -18.12}
]The data accessors look a little nicer by using lenses:
import Control.Lens
w <- fromJust <$> ForecastDaily.fromCoords key Owm.Metric Owm.ES (Owm.Coords 90.0 180.0) (Count 6) -- 6 12h intervals
cod = w ^. ForecastDaily._forecastDailyCod
dts = w ^. ForecastDaily._forecastDailyList ^.. traverse . ForecastDaily._listEltDt
temps = w ^. ForecastDaily._forecastDailyList ^.. traverse . ForecastDaily._listEltTempOWM represents timestamps as UNIX epoch Doubles. Use toUTCTime :: Double -> UTCTime to convert to a proper time stamp.
print $ zip (toUTCTome <$> dts) tempsThis gives a result like
(2018-11-9 05:00:00 UTC,Temp {tempMax = -17.8, tempDay = -17.94, tempNight = -20.45, tempMin = -20.45, tempMorn = -17.8, tempEve = -18.76})
(2018-11-9 11:00:00 UTC,Temp {tempMax = -21.33, tempDay = -22.4, tempNight = -21.33, tempMin = -22.4, tempMorn = -22.4, tempEve = -22.35})
(2018-11-10 05:00:00 UTC,Temp {tempMax = -17.7, tempDay = -20.14, tempNight = -17.7, tempMin = -21.33, tempMorn = -21.33, tempEve = -18.12})
(2018-11-10 11:00:00 UTC,Temp {tempMax = -17.7, tempDay = -18.12, tempNight = -18.52, tempMin = -20.14, tempMorn = -20.14, tempEve = -17.7})
(2018-11-11 05:00:00 UTC,Temp {tempMax = -18.52, tempDay = -20.73, tempNight = -19.17, tempMin = -20.73, tempMorn = -18.52, tempEve = -20.68})
(2018-11-11 11:00:00 UTC,Temp {tempMax = -18.05, tempDay = -20.68, tempNight = -18.05, tempMin = -20.73, tempMorn = -20.73, tempEve = -19.17})The JSON generators/parsers are auto-generated with the help of json-autotype. This approach has advantages and disadvantages: No effort is spent on writing ToJSON and FromJSON instances, so it's easy to adapt and extend the library. The downside are not very intuitive naming and an abundance of name-clashes, resulting in lengthy (qualified) function names.
json-autotype does automatic type inference from JSON input.
# installation:
stack install json-autotype runghc
JSON input is generated with GetJsonExamples.hs, it will write files into the folder json.
TODO:
- Explain the setup
- Add some tests