Skip to content

mayeranalytics/haskell-owm

Repository files navigation

OpenWeatherMap

Overview

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.

Wikipedia

Coverage:

Getting Started

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-owm

Usage

import 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 f

Current weather is obtained by calling one of the functions in Network.Owm.Weather,

weather <- Weather.fromCityId key Owm.Metric Owm.EN (CityId 2172797)
print weather

All functions require the arguments Units and Lang. For example, Units is defined as

data Units = Metric | Standard | Imperial	-- src/Network/Owm/Owm.hs

Similarly, 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 DefaultCountry

Forecast 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._listEltTemp

OWM represents timestamps as UNIX epoch Doubles. Use toUTCTime :: Double -> UTCTime to convert to a proper time stamp.

print $ zip (toUTCTome <$> dts) temps

This 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})

About the API

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

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