Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show hourly forecast #455

Merged
merged 7 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion weather-api-widget/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ following config parameters:
| units | `metric` | `metric` for celsius, `imperial` for fahrenheit |
| icon_pack_name | `weather-underground-icons` | Name of the icon pack, could be `weather-underground-icon` or `VitalyGorbachev` or create your own, more details below |
| icons_extension | `.png` | File extension of icons in the pack |
| show_forecast | false | Show forecast for next three days |
| show_daily_forecast | false | Show forecast for next three days |
| show_hourly_forecast | false | Show hourly forecast section |
| timeout | 120 | How often in seconds the widget refreshes |

### Icons:
Expand Down
194 changes: 188 additions & 6 deletions weather-api-widget/weather.lua
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,16 @@ local function worker(user_args)
local api_key = args.api_key
local font_name = args.font_name or beautiful.font:gsub("%s%d+$", "")
local units = args.units or 'metric'
local time_format_12h = args.time_format_12h
local both_units_widget = args.both_units_widget or false
local icon_pack_name = args.icons or 'weather-underground-icons'
local icons_extension = args.icons_extension or '.png'
local show_forecast = args.show_forecast or false
local show_daily_forecast = args.show_daily_forecast or false
local show_hourly_forecast = args.show_hourly_forecast or false
local timeout = args.timeout or 120

local ICONS_DIR = WIDGET_DIR .. '/icons/' .. icon_pack_name .. '/'
-- Forecast endpoint includes current. I could map show_forecast to days here.
-- Forecast endpoint includes current. I could map show_daily_forecast to days here.
-- Currently overfetching but only showing when opting in.
local weather_api =
('https://api.weatherapi.com/v1/forecast.json' ..
Expand Down Expand Up @@ -304,7 +306,7 @@ local function worker(user_args)
end
}

local forecast_widget = {
local daily_forecast_widget = {
forced_width = 300,
layout = wibox.layout.flex.horizontal,
update = function(self, forecast)
Expand Down Expand Up @@ -364,6 +366,181 @@ local function worker(user_args)
end
}

local hourly_forecast_graph = wibox.widget {
step_width = 12,
color = '#EBCB8B',
background_color = beautiful.bg_normal,
forced_height = 100,
forced_width = 300,
widget = wibox.widget.graph,
set_max_value = function(self, new_max_value)
self.max_value = new_max_value
end,
set_min_value = function(self, new_min_value)
self.min_value = new_min_value
end,
}

local hourly_forecast_negative_graph = wibox.widget {
step_width = 12,
color = '#5E81AC',
background_color = beautiful.bg_normal,
forced_height = 100,
forced_width = 300,
widget = wibox.widget.graph,
set_max_value = function(self, new_max_value)
self.max_value = new_max_value
end,
set_min_value = function(self, new_min_value)
self.min_value = new_min_value
end,
}

local hourly_forecast_widget = {
layout = wibox.layout.fixed.vertical,
update = function(self, hourly)
local hours_below = {
id = 'hours',
forced_width = 300,
layout = wibox.layout.flex.horizontal
}
local temp_below = {
id = 'temp',
forced_width = 300,
layout = wibox.layout.flex.horizontal
}

local max_temp = -1000
local min_temp = 1000
local values= {}

-- Yeah, this looks weird. I would expect to have to use ipairs
for i, hour in pairs(hourly) do
if i > 25 then
break
end

values[i] = hour.temp_c

if max_temp < hour.temp_c then
max_temp = hour.temp_c
end

if min_temp > hour.temp_c then
min_temp = hour.temp_c
end

if (i - 1) % 5 == 0 then
table.insert(hours_below, wibox.widget {
text = os.date(time_format_12h and '%I%p' or '%H:00', tonumber(hour.time_epoch)),
align = 'center',
font = font_name .. ' 9',
widget = wibox.widget.textbox
})

table.insert(temp_below, wibox.widget {
markup = '<span foreground=""'
Ryuno-Ki marked this conversation as resolved.
Show resolved Hide resolved
.. (tonumber(hour.temp_c) > 0 and '#2E3440' or '#ECEFF4') .. '">'
.. string.format('%.0f', hour.temp_c) .. '°' .. '</span>',
align = 'center',
font = font_name .. ' 9',
widget = wibox.widget.textbox
})
end
end

hourly_forecast_graph:set_max_value(math.max(max_temp, math.abs(min_temp)))
hourly_forecast_graph:set_min_value(min_temp > 0 and min_temp * 0.7 or 0) -- move graph a bit up

hourly_forecast_negative_graph:set_max_value(math.abs(min_temp))
hourly_forecast_negative_graph:set_min_value(max_temp < 0 and math.abs(max_temp) * 0.7 or 0)

for _, value in ipairs(values) do
if value >= 0 then
hourly_forecast_graph:add_value(value)
hourly_forecast_negative_graph:add_value(0)
else
hourly_forecast_graph:add_value(0)
hourly_forecast_negative_graph:add_value(math.abs(value))
end
end

local count = #self
for i = 0, count do
self[i] = nil
end

-- all temperatures are positive
if min_temp > 0 then
table.insert(self, wibox.widget {
{
hourly_forecast_graph,
reflection = { horizontal = true },
widget = wibox.container.mirror
},
{
temp_below,
valign = 'bottom',
widget = wibox.container.place
},
id = 'graph',
layout = wibox.layout.stack
})
table.insert(self, hours_below)

-- all temperatures are negative
elseif max_temp < 0 then
table.insert(self, hours_below)
table.insert(self, wibox.widget {
{
hourly_forecast_negative_graph,
reflection = { horizontal = true, vertical = true },
widget = wibox.container.mirror
},
{
temp_below,
valign = 'top',
widget = wibox.container.place
},
id = 'graph',
layout = wibox.layout.stack
})

-- mixed temperatures
else
table.insert(self, wibox.widget {
{
hourly_forecast_graph,
reflection = { horizontal = true },
widget = wibox.container.mirror
},
{
temp_below,
valign = 'bottom',
widget = wibox.container.place
},
id = 'graph',
layout = wibox.layout.stack
})

table.insert(self, wibox.widget {
{
hourly_forecast_negative_graph,
reflection = { horizontal = true, vertical = true },
widget = wibox.container.mirror
},
{
temp_below,
valign = 'top',
widget = wibox.container.place
},
id = 'graph',
layout = wibox.layout.stack
})
end
end
}

local function update_widget(widget, stdout, stderr)
if stderr ~= '' then
if not warning_shown then
Expand Down Expand Up @@ -411,9 +588,14 @@ local function worker(user_args)
}


if show_forecast then
forecast_widget:update(result.forecast.forecastday)
table.insert(final_widget, forecast_widget)
if show_hourly_forecast then
hourly_forecast_widget:update(result.forecast.forecastday[1].hour)
table.insert(final_widget, hourly_forecast_widget)
end

if show_daily_forecast then
daily_forecast_widget:update(result.forecast.forecastday)
table.insert(final_widget, daily_forecast_widget)
end

weather_popup:setup({
Expand Down
Loading