2021-11-29 19:57:00 +11:00

399 lines
9.7 KiB
Lua

local wibox = require('wibox')
local awful = require('awful')
local gears = require('gears')
local naughty = require('naughty')
local beautiful = require('beautiful')
local dpi = beautiful.xresources.apply_dpi
local config_dir = gears.filesystem.get_configuration_dir()
local widget_icon_dir = config_dir .. 'widget/weather/icons/'
local clickable_container = require('widget.clickable-container')
local json = require('library.json')
local config = require('configuration.config')
local secrets = {
key = config.widget.weather.key,
city_id = config.widget.weather.city_id,
units = config.widget.weather.units,
update_interval = config.widget.weather.update_interval
}
local weather_icon_widget = wibox.widget {
{
id = 'icon',
image = widget_icon_dir .. 'weather-error.svg',
resize = true,
forced_height = dpi(45),
forced_width = dpi(45),
widget = wibox.widget.imagebox,
},
layout = wibox.layout.fixed.horizontal
}
local sunrise_icon_widget = wibox.widget {
{
id = 'sunrise_icon',
image = widget_icon_dir .. 'sunrise.svg',
resize = true,
forced_height = dpi(18),
forced_width = dpi(18),
widget = wibox.widget.imagebox,
},
layout = wibox.layout.fixed.horizontal
}
local sunset_icon_widget = wibox.widget {
{
id = 'sunset_icon',
image = widget_icon_dir .. 'sunset.svg',
resize = true,
forced_height = dpi(18),
forced_width = dpi(18),
widget = wibox.widget.imagebox,
},
layout = wibox.layout.fixed.horizontal
}
local refresh_icon_widget = wibox.widget {
{
id = 'refresh_icon',
image = widget_icon_dir .. 'refresh.svg',
resize = true,
forced_height = dpi(18),
forced_width = dpi(18),
widget = wibox.widget.imagebox,
},
layout = wibox.layout.fixed.horizontal
}
local refresh_button = clickable_container(refresh_icon_widget)
refresh_button:buttons(
gears.table.join(
awful.button(
{},
1,
nil,
function()
awesome.emit_signal('widget::weather_fetch')
awesome.emit_signal('widget::forecast_fetch')
end
)
)
)
local refresh_widget = wibox.widget {
refresh_button,
bg = beautiful.transparent,
shape = gears.shape.circle,
widget = wibox.container.background
}
local weather_desc_temp = wibox.widget {
{
id = 'description',
markup = 'Dust and clouds, -1000°C',
font = 'Inter Regular 10',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
},
id = 'scroll_container',
max_size = 345,
speed = 75,
expand = true,
direction = 'h',
step_function = wibox.container.scroll
.step_functions.waiting_nonlinear_back_and_forth,
fps = 30,
layout = wibox.container.scroll.horizontal,
}
local weather_location = wibox.widget {
{
id = 'location',
markup = 'Earth, Milky Way',
font = 'Inter Regular 10',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
},
id = 'scroll_container',
max_size = 345,
speed = 75,
expand = true,
direction = 'h',
step_function = wibox.container.scroll
.step_functions.waiting_nonlinear_back_and_forth,
fps = 30,
layout = wibox.container.scroll.horizontal,
}
local weather_sunrise = wibox.widget {
markup = '00:00',
font = 'Inter Regular 10',
align = 'center',
valign = 'center',
widget = wibox.widget.textbox
}
local weather_sunset = wibox.widget {
markup = '00:00',
font = 'Inter Regular 10',
align = 'center',
valign = 'center',
widget = wibox.widget.textbox
}
local weather_data_time = wibox.widget {
markup = '00:00',
font = 'Inter Regular 10',
align = 'center',
valign = 'center',
widget = wibox.widget.textbox
}
local weather_forecast_tooltip = awful.tooltip {
text = 'Loading...',
objects = {weather_icon_widget},
mode = 'outside',
align = 'right',
preferred_positions = {'left', 'right', 'top', 'bottom'},
margin_leftright = dpi(8),
margin_topbottom = dpi(8)
}
local weather_report = wibox.widget {
{
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(10),
{
layout = wibox.layout.align.vertical,
expand = 'none',
nil,
weather_icon_widget,
nil
},
{
layout = wibox.layout.align.vertical,
expand = 'none',
nil,
{
layout = wibox.layout.fixed.vertical,
weather_location,
weather_desc_temp,
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(7),
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(3),
sunrise_icon_widget,
weather_sunrise
},
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(3),
sunset_icon_widget,
weather_sunset
},
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(3),
refresh_widget,
weather_data_time
}
}
},
nil
}
},
margins = dpi(10),
widget = wibox.container.margin
},
forced_height = dpi(92),
bg = beautiful.groups_bg,
shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, true, true, beautiful.groups_radius)
end,
widget = wibox.container.background
}
-- Return weather symbol
local get_weather_symbol = function()
local symbol_tbl = {
['metric'] = '°C',
['imperial'] = '°F'
}
return symbol_tbl[secrets.units]
end
-- Create openweathermap script based on pass mode
-- Mode must be `forecast` or `weather`
local create_weather_script = function(mode)
local weather_script = [[
KEY="]] .. secrets.key .. [["
CITY="]] .. secrets.city_id .. [["
UNITS="]] .. secrets.units .. [["
weather=$(curl -sf "http://api.openweathermap.org/data/2.5/]] .. mode ..
[[?APPID="${KEY}"&id="${CITY}"&units="${UNITS}"")
if [ ! -z "$weather" ]; then
printf "${weather}"
else
printf "error"
fi
]]
return weather_script
end
awesome.connect_signal(
'widget::forecast_fetch',
function()
awful.spawn.easy_async_with_shell(
create_weather_script('forecast'),
function(stdout)
if stdout:match('error') then
weather_forecast_tooltip:set_markup('Can\'t retrieve data!')
else
local forecast_data = json.parse(stdout)
local forecast = ''
for i = 8, 40, 8 do
local day = os.date('%A @ %H:%M', forecast_data.list[i].dt)
local temp = math.floor(forecast_data.list[i].main.temp + 0.5)
local feels_like = math.floor(forecast_data.list[i].main.feels_like + 0.5)
local weather = forecast_data.list[i].weather[1].description
-- Capitalize weather description
weather = weather:sub(1, 1):upper() .. weather:sub(2)
forecast = forecast .. '<b>' .. day .. '</b>\n' ..
'Weather: ' .. weather .. '\n' ..
'Temperature: ' .. temp .. get_weather_symbol() .. '\n' ..
'Feels like: ' .. feels_like .. get_weather_symbol() .. '\n\n'
weather_forecast_tooltip:set_markup(forecast:sub(1, -2))
end
end
end
)
end
)
awesome.connect_signal(
'widget::weather_fetch',
function()
awful.spawn.easy_async_with_shell(
create_weather_script('weather'),
function(stdout)
if stdout:match('error') then
awesome.emit_signal(
'widget::weather_update',
'...',
'Dust and clouds, -1000°C',
'Earth, Milky Way',
'00:00',
'00:00',
'00:00'
)
else
-- Parse JSON string
local weather_data = json.parse(stdout)
-- Process weather data
local location = weather_data.name
local country = weather_data.sys.country
local sunrise = os.date('%H:%M', weather_data.sys.sunrise)
local sunset = os.date('%H:%M', weather_data.sys.sunset)
local refresh = os.date('%H:%M', weather_data.dt)
local temperature = math.floor(weather_data.main.temp + 0.5)
local weather = weather_data.weather[1].description
local weather_icon = weather_data.weather[1].icon
-- Capitalize weather description
local weather = weather:sub(1, 1):upper() .. weather:sub(2)
-- Contantenate weather description and symbol
local weather_description = weather .. ', ' .. temperature .. get_weather_symbol()
-- Contantenate city and country
local weather_location = location .. ', ' .. country
awesome.emit_signal(
'widget::weather_update',
weather_icon,
weather_description,
weather_location,
sunrise,
sunset,
refresh
)
end
end
)
end
)
local update_widget_timer = gears.timer {
timeout = secrets.update_interval,
autostart = true,
call_now = true,
single_shot = false,
callback = function()
awesome.emit_signal('widget::weather_fetch')
awesome.emit_signal('widget::forecast_fetch')
end
}
awesome.connect_signal(
'system::network_connected',
function()
awesome.emit_signal('widget::weather_fetch')
awesome.emit_signal('widget::forecast_fetch')
end
)
awesome.connect_signal(
'widget::weather_update',
function(code, desc, location, sunrise, sunset, data_receive)
local widget_icon_name = 'weather-error'
local icon_tbl = {
['01d'] = 'sun_icon.svg',
['01n'] = 'moon_icon.svg',
['02d'] = 'dfew_clouds.svg',
['02n'] = 'nfew_clouds.svg',
['03d'] = 'dscattered_clouds.svg',
['03n'] = 'nscattered_clouds.svg',
['04d'] = 'dbroken_clouds.svg',
['04n'] = 'nbroken_clouds.svg',
['09d'] = 'dshower_rain.svg',
['09n'] = 'nshower_rain.svg',
['10d'] = 'd_rain.svg',
['10n'] = 'n_rain.svg',
['11d'] = 'dthunderstorm.svg',
['11n'] = 'nthunderstorm.svg',
['13d'] = 'snow.svg',
['13n'] = 'snow.svg',
['50d'] = 'dmist.svg',
['50n'] = 'nmist.svg',
['...'] = 'weather-error.svg'
}
widget_icon_name = icon_tbl[code]
weather_icon_widget.icon:set_image(widget_icon_dir .. widget_icon_name)
weather_icon_widget.icon:emit_signal('widget::redraw_needed')
weather_desc_temp.description:set_markup(desc)
weather_location.location:set_markup(location)
weather_sunrise:set_markup(sunrise)
weather_sunset:set_markup(sunset)
weather_data_time:set_markup(data_receive)
end
)
return weather_report