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
|
-- 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
-- OWM's metric units report wind in m/s. The card shows km/h.
function M.kmh(ms)
if type(ms) ~= 'number' then return nil end
return ms * 3.6
end
-- Beaufort force from km/h. Upper bounds carried over from the polybar
-- script; a value equal to a bound stays in the lower force.
local BEAUFORT = { 1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117 }
function M.beaufort(kmh)
if type(kmh) ~= 'number' then return nil end
for force, bound in ipairs(BEAUFORT) do
if kmh <= bound then return force - 1 end
end
return 12
end
-- Eight compass points. The half-step offset is what makes north straddle
-- zero: without it, 350 degrees would land in NW and 10 in NE, leaving north
-- with only half its arc.
local POINTS = { 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW' }
function M.compass(deg)
if type(deg) ~= 'number' then return nil end
local i = math.floor(((deg % 360) + 22.5) / 45) % 8
return POINTS[i + 1]
end
-- Arrow glyphs, in the same order as POINTS but rotated half a turn: OWM
-- reports the direction the wind comes FROM, and an arrow reads as the
-- direction it goes TO.
local ARROWS = { '\u{2193}', '\u{2199}', '\u{2190}', '\u{2196}',
'\u{2191}', '\u{2197}', '\u{2192}', '\u{2198}' }
function M.arrow(deg)
if type(deg) ~= 'number' then return '' end
local i = math.floor(((deg % 360) + 22.5) / 45) % 8
return ARROWS[i + 1]
end
return M
|