1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
module Print
( printCurrectWeather
, printForecastWeather
) where
import Data.List (intercalate)
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Data.Time.LocalTime (TimeZone, minutesToTimeZone, utcToZonedTime)
import Text.Printf (printf)
import Web.OpenWeatherMap.Formulas (absoluteHumidity)
import qualified Web.OpenWeatherMap.Types.City as City
import qualified Web.OpenWeatherMap.Types.Coord as Coord
import qualified Web.OpenWeatherMap.Types.CurrentWeather as CW
import qualified Web.OpenWeatherMap.Types.Forecast as FC
import qualified Web.OpenWeatherMap.Types.ForecastWeather as FW
import qualified Web.OpenWeatherMap.Types.Main as Main
import qualified Web.OpenWeatherMap.Types.Sys as Sys
import qualified Web.OpenWeatherMap.Types.Weather as Weather
import qualified Web.OpenWeatherMap.Types.Wind as Wind
printCurrectWeather :: CW.CurrentWeather -> IO ()
printCurrectWeather cw =
putStrLn
(place ++
", " ++
time ++
": " ++
intercalate
", "
[ w
, showHumidity mainw
, showAbsoluteHumidity mainw
, showPressure mainw
, showTemp mainw
, showWind wind
])
where
tz = secondsToTimeZone (CW.timezone cw)
time = showLocalTime tz (CW.dt cw)
w = showWeather $ CW.weather cw
place = showLocation (CW.name cw) (Sys.country . CW.sys $ cw) (CW.coord cw)
mainw = CW.main cw
wind = CW.wind cw
printForecastWeather :: FW.ForecastWeather -> IO ()
printForecastWeather fw = do
let c = FW.city fw
tz = secondsToTimeZone (City.timezone c)
place = showLocation (City.name c) (City.country c) (City.coord c)
putStrLn place
mapM_ putStrLn (showForecast tz <$> FW.list fw)
secondsToTimeZone :: Int -> TimeZone
secondsToTimeZone s = minutesToTimeZone (s `div` 60)
showForecast :: TimeZone -> FC.Forecast -> String
showForecast tz fc =
showLocalTime tz (FC.dt fc) ++
": " ++
intercalate
", "
[ showWeather (FC.weather fc)
, showHumidity mainw
, showAbsoluteHumidity mainw
, showPressure mainw
, showTemp mainw
, showWind (FC.wind fc)
]
where
mainw = FC.main fc
showLocalTime :: TimeZone -> Int -> String
showLocalTime tz =
show . utcToZonedTime tz . posixSecondsToUTCTime . fromIntegral
showLocation :: String -> Maybe String -> Coord.Coord -> String
showLocation name country coord =
name' ++ maybe "" ("," ++) country ++ " " ++ coords
where
coords = showCoord coord
name' =
if name /= ""
then name
else "<unknown>"
showCoord :: Coord.Coord -> String
showCoord coord =
"(" ++
maybe "?" show (Coord.lat coord) ++
"°, " ++ maybe "?" show (Coord.lon coord) ++ "°)"
showWeather :: [Weather.Weather] -> String
showWeather w = intercalate "/" $ Weather.main <$> w
showHumidity :: Main.Main -> String
showHumidity m = "H " ++ show hm ++ " %"
where
hm :: Int
hm = round . Main.humidity $ m
showAbsoluteHumidity :: Main.Main -> String
showAbsoluteHumidity m = "ρ " ++ rho ++ " g/m³"
where
r = absoluteHumidity m
rho = maybe "??" (printf "%0.2f") r
-- https://en.wikipedia.org/wiki/Millimeter_of_mercury
showPressure :: Main.Main -> String
showPressure m = "P " ++ show p ++ " mmHg"
where
hPa2mmHg hpa = hpa * 0.750061561303
p :: Int
p = round . hPa2mmHg . Main.pressure $ m
-- https://stackoverflow.com/q/7490660/933161
showWind :: Wind.Wind -> String
showWind w = dir ++ " " ++ show speed ++ " m/s"
where
speed :: Int
speed = round . Wind.speed $ w
deg = Wind.deg w
-- [ "N", "NE", "E", "SE", "S", "SW", "W", "NW" ]
dirs = ["↓", "↙", "←", "↖", "↑", "↗", "→", "↘"]
l = length dirs
sector = round $ (deg * fromIntegral l) / 360.0
dir = dirs !! (sector `rem` l)
showTemp :: Main.Main -> String
showTemp m = "T " ++ temp ++ " °C"
where
k2c k = k - 273.15 -- Kelvin to Celsius
tmax :: Int
tmin :: Int
tmax = round . k2c . Main.temp_max $ m
tmin = round . k2c . Main.temp_min $ m
show' t =
if t > 0
then "+" ++ show t
else show t
temp =
if tmax /= tmin
then show' tmin ++ ".." ++ show' tmax
else show' tmin
|