aboutsummaryrefslogtreecommitdiffstats
path: root/lib/weather.lua
blob: 0b4b1b78150b8dc0b0838fc8157694070f73d0b1 (plain)
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
-- OpenWeatherMap domain knowledge and cache parsing.
--
-- Separate from lib/data.lua: that reads /proc and /sys, this reads a cached
-- HTTP response and carries its own tables. Same testable shape though, every
-- function takes a string or numbers and returns a value, so the tests need no
-- filesystem and no network.
--
-- Nothing here raises. A Lua error in this project is a blank screen, so every
-- parse path returns nil and lets the widget draw its "no data" state.

local M = {}

-- Nerd Font codepoints, all present in Inconsolata Nerd Font (card.FONT_MONO).
-- Verified by rendering the glyphs and looking at them, not by fontconfig
-- alone: a missing glyph draws as an invisible blank rather than an error.
M.ICON = {
  thunder_day       = '\u{E30F}',
  thunder_night     = '\u{E32A}',
  drizzle_day       = '\u{E306}',
  drizzle_night     = '\u{E326}',
  drizzle_heavy_day = '\u{E308}',
  drizzle_heavy_night = '\u{E325}',
  rain_day          = '\u{E308}',
  rain_night        = '\u{E325}',
  snow              = '\u{E31A}',
  fog               = '\u{E313}',
  tornado           = '\u{E351}',
  clear_day         = '\u{E30D}',
  clear_night       = '\u{E32B}',
  few_day           = '\u{E302}',
  few_night         = '\u{E379}',
  overcast          = '\u{E312}',
  unknown           = '\u{E374}',
  sunrise           = '\u{E34C}',
  sunset            = '\u{E34D}',
}

-- Condition id to icon, by upper bound. Ported from the polybar script's
-- accumulated knowledge; the ranges are not round hundreds.
-- `now`, `sunrise` and `sunset` are unix timestamps and pick the day or night
-- face for the conditions that have both.
function M.icon(id, now, sunrise, sunset)
  if type(id) ~= 'number' then return M.ICON.unknown end
  -- `now` is guarded alongside sunrise and sunset, not just them: comparing a
  -- nil now against a number raises, and a raise here is a blank dashboard.
  -- Missing any of the three means the sun is unknown, so the day face is
  -- drawn, which is what is_day() falls back to as well.
  local day = true
  if now and sunrise and sunset then day = (now >= sunrise and now <= sunset) end
  local function pick(d, n) return day and d or n end

  if id <= 232 then return pick(M.ICON.thunder_day, M.ICON.thunder_night)
  elseif id <= 311 then return pick(M.ICON.drizzle_day, M.ICON.drizzle_night)
  elseif id <= 321 then return pick(M.ICON.drizzle_heavy_day, M.ICON.drizzle_heavy_night)
  elseif id <= 531 then return pick(M.ICON.rain_day, M.ICON.rain_night)
  elseif id <= 622 then return M.ICON.snow
  elseif id <= 771 then return M.ICON.fog
  elseif id == 781 then return M.ICON.tornado
  elseif id == 800 then return pick(M.ICON.clear_day, M.ICON.clear_night)
  elseif id == 801 then return pick(M.ICON.few_day, M.ICON.few_night)
  elseif id <= 804 then return M.ICON.overcast
  end
  return M.ICON.unknown
end

return M