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