diff options
Diffstat (limited to 'weather-widget')
-rw-r--r-- | weather-widget/README.md | 35 | ||||
-rw-r--r-- | weather-widget/weather.lua | 341 |
2 files changed, 211 insertions, 165 deletions
diff --git a/weather-widget/README.md b/weather-widget/README.md index ef7282f..6464fcc 100644 --- a/weather-widget/README.md +++ b/weather-widget/README.md @@ -4,6 +4,30 @@ Note that widget uses the Arc icon theme, so it should be [installed](https://github.com/horst3180/arc-icon-theme#installation) first under **/usr/share/icons/Arc/** folder. +## Customization + +It is possible to customize widget by providing a table with all or some of the following config parameters: + +| Name | Default | Description | +|---|---|---| +| `font` | `Play 9` | Font | +| `city` | `Montreal,ca` | City name and country code, [more info](https://openweathermap.org/current) | +| `api_key` | none| API key, required | +| `units` | `metric` | `metric` for celsius, `imperial` for fahrenheit | +| `both_units_widget` | `false` | show temperature in both units (15°C (59°F)) or in one (15°C) | +| `both_units_popup` | `false` | same as above but for popup | + +### Example: + +```lua +weather_widget({ + api_key = 'your-api-key', + units = 'imperial', + font = 'Ubuntu Mono 9' +}), +``` + + ## Installation 1. Install lua socket - to make HTTP calls to get the weather information. @@ -24,7 +48,7 @@ Note that widget uses the Arc icon theme, so it should be [installed](https://gi git clone https://github.com/streetturtle/awesome-wm-widgets.git ~/.config/awesome/ ``` -1. Get Open Weather Map app id here: [openweathermap.org/appid](https://openweathermap.org/appid) and place it in **~/.config/awesome/awesome-wm-widgets/secrets.lua**, or directly in the widget. Don't forget to set also your city and units - C/F. +1. Get Open Weather Map app id here: [openweathermap.org/appid](https://openweathermap.org/appid). 1. Require weather widget at the beginning of **rc.lua**: @@ -39,7 +63,14 @@ Note that widget uses the Arc icon theme, so it should be [installed](https://gi { -- Right widgets layout = wibox.layout.fixed.horizontal, ... - weather_widget, + --default + weather_widget({api_key = 'your-api-key'}), + --customized + weather_widget({ + api_key = 'your-api-key', + units = 'imperial', + font = 'Ubuntu Mono 9' + }) ... ``` diff --git a/weather-widget/weather.lua b/weather-widget/weather.lua index d6693cf..b0aa070 100644 --- a/weather-widget/weather.lua +++ b/weather-widget/weather.lua @@ -14,182 +14,197 @@ local naughty = require("naughty") local wibox = require("wibox") local gears = require("gears") -local secrets = require("awesome-wm-widgets.secrets") - -local weather_api_url = ( - 'https://api.openweathermap.org/data/2.5/weather' - .. '?q=' .. secrets.weather_widget_city - .. '&appid=' .. secrets.weather_widget_api_key - .. '&units=' .. secrets.weather_widget_units -) - local path_to_icons = "/usr/share/icons/Arc/status/symbolic/" -local icon_widget = wibox.widget { - { - id = "icon", - resize = false, - widget = wibox.widget.imagebox, - }, - layout = wibox.container.margin(_ , 0, 0, 3), - set_image = function(self, path) - self.icon.image = path - end, -} - -local temp_widget = wibox.widget{ - font = "Play 9", - widget = wibox.widget.textbox, -} - -local weather_widget = wibox.widget { - icon_widget, - temp_widget, - layout = wibox.layout.fixed.horizontal, -} - ---- Maps openWeatherMap icons to Arc icons -local icon_map = { - ["01d"] = "weather-clear-symbolic.svg", - ["02d"] = "weather-few-clouds-symbolic.svg", - ["03d"] = "weather-clouds-symbolic.svg", - ["04d"] = "weather-overcast-symbolic.svg", - ["09d"] = "weather-showers-scattered-symbolic.svg", - ["10d"] = "weather-showers-symbolic.svg", - ["11d"] = "weather-storm-symbolic.svg", - ["13d"] = "weather-snow-symbolic.svg", - ["50d"] = "weather-fog-symbolic.svg", - ["01n"] = "weather-clear-night-symbolic.svg", - ["02n"] = "weather-few-clouds-night-symbolic.svg", - ["03n"] = "weather-clouds-night-symbolic.svg", - ["04n"] = "weather-overcast-symbolic.svg", - ["09n"] = "weather-showers-scattered-symbolic.svg", - ["10n"] = "weather-showers-symbolic.svg", - ["11n"] = "weather-storm-symbolic.svg", - ["13n"] = "weather-snow-symbolic.svg", - ["50n"] = "weather-fog-symbolic.svg" -} - ---- Return wind direction as a string. -local function to_direction(degrees) - -- Ref: https://www.campbellsci.eu/blog/convert-wind-directions - if degrees == nil then - return "Unknown dir" - end - local directions = { - "N", - "NNE", - "NE", - "ENE", - "E", - "ESE", - "SE", - "SSE", - "S", - "SSW", - "SW", - "WSW", - "W", - "WNW", - "NW", - "NNW", - "N", +local weather_widget = {} + +local function worker(args) + + local args = args or {} + + local font = args.font or 'Play 9' + local city = args.city or 'Montreal,ca' + local api_key = args.api_key or naughty.notify{preset = naughty.config.presets.critical, text = 'OpenweatherMap API key is not set'} + local units = args.units or 'metric' + local both_units_widget = args.both_units_widget or false + local both_units_popup = args.both_units_popup or false + + local weather_api_url = ( + 'https://api.openweathermap.org/data/2.5/weather' + .. '?q=' .. city + .. '&appid=' .. api_key + .. '&units=' .. units + ) + + local icon_widget = wibox.widget { + { + id = "icon", + resize = false, + widget = wibox.widget.imagebox, + }, + layout = wibox.container.margin(_, 0, 0, 3), + set_image = function(self, path) + self.icon.image = path + end, } - return directions[math.floor((degrees % 360) / 22.5) + 1] -end --- Convert degrees Celsius to Fahrenheit -local function celsius_to_fahrenheit(c) - return c*9/5+32 -end + local temp_widget = wibox.widget { + font = font, + widget = wibox.widget.textbox, + } --- Convert degrees Fahrenheit to Celsius -local function fahrenheit_to_celsius(f) - return (f-32)*5/9 -end + weather_widget = wibox.widget { + icon_widget, + temp_widget, + layout = wibox.layout.fixed.horizontal, + } + + --- Maps openWeatherMap icons to Arc icons + local icon_map = { + ["01d"] = "weather-clear-symbolic.svg", + ["02d"] = "weather-few-clouds-symbolic.svg", + ["03d"] = "weather-clouds-symbolic.svg", + ["04d"] = "weather-overcast-symbolic.svg", + ["09d"] = "weather-showers-scattered-symbolic.svg", + ["10d"] = "weather-showers-symbolic.svg", + ["11d"] = "weather-storm-symbolic.svg", + ["13d"] = "weather-snow-symbolic.svg", + ["50d"] = "weather-fog-symbolic.svg", + ["01n"] = "weather-clear-night-symbolic.svg", + ["02n"] = "weather-few-clouds-night-symbolic.svg", + ["03n"] = "weather-clouds-night-symbolic.svg", + ["04n"] = "weather-overcast-symbolic.svg", + ["09n"] = "weather-showers-scattered-symbolic.svg", + ["10n"] = "weather-showers-symbolic.svg", + ["11n"] = "weather-storm-symbolic.svg", + ["13n"] = "weather-snow-symbolic.svg", + ["50n"] = "weather-fog-symbolic.svg" + } -local weather_timer = gears.timer({ timeout = 60 }) -local resp - -local function gen_temperature_str(temp, fmt_str, show_other_units) - local temp_str = string.format(fmt_str, temp) - local s = temp_str .. '°' .. (secrets.weather_widget_units == 'metric' and 'C' or 'F') - - if (show_other_units) then - local temp_conv, units_conv - if (secrets.weather_widget_units == 'metric') then - temp_conv = celsius_to_fahrenheit(temp) - units_conv = 'F' - else - temp_conv = fahrenheit_to_celsius(temp) - units_conv = 'C' + --- Return wind direction as a string. + local function to_direction(degrees) + -- Ref: https://www.campbellsci.eu/blog/convert-wind-directions + if degrees == nil then + return "Unknown dir" end + local directions = { + "N", + "NNE", + "NE", + "ENE", + "E", + "ESE", + "SE", + "SSE", + "S", + "SSW", + "SW", + "WSW", + "W", + "WNW", + "NW", + "NNW", + "N", + } + return directions[math.floor((degrees % 360) / 22.5) + 1] + end - local temp_conv_str = string.format(fmt_str, temp_conv) - s = s .. ' ' .. '('.. temp_conv_str .. '°' .. units_conv .. ')' + -- Convert degrees Celsius to Fahrenheit + local function celsius_to_fahrenheit(c) + return c*9/5+32 + end + + -- Convert degrees Fahrenheit to Celsius + local function fahrenheit_to_celsius(f) + return (f-32)*5/9 end - return s -end -weather_timer:connect_signal("timeout", function () - local resp_json = {} - local res, status = http.request{ - url=weather_api_url, - sink=ltn12.sink.table(resp_json), - -- ref: - -- http://w3.impa.br/~diego/software/luasocket/old/luasocket-2.0/http.html - create=function() - -- ref: https://stackoverflow.com/a/6021774/595220 - local req_sock = socket.tcp() - -- 't' — overall timeout - req_sock:settimeout(0.2, 't') - -- 'b' — block timeout - req_sock:settimeout(0.001, 'b') - return req_sock + local weather_timer = gears.timer({ timeout = 60 }) + local resp + + local function gen_temperature_str(temp, fmt_str, show_other_units) + local temp_str = string.format(fmt_str, temp) + local s = temp_str .. '°' .. (units == 'metric' and 'C' or 'F') + + if (show_other_units) then + local temp_conv, units_conv + if (units == 'metric') then + temp_conv = celsius_to_fahrenheit(temp) + units_conv = 'F' + else + temp_conv = fahrenheit_to_celsius(temp) + units_conv = 'C' + end + + local temp_conv_str = string.format(fmt_str, temp_conv) + s = s .. ' ' .. '('.. temp_conv_str .. '°' .. units_conv .. ')' end - } - if (resp_json ~= nil) then - resp_json = table.concat(resp_json) + return s end - if (status ~= 200 and resp_json ~= nil and resp_json ~= '') then - local err_resp = json.decode(resp_json) - naughty.notify{ - title = 'Weather Widget Error', - text = err_resp.message, - preset = naughty.config.presets.critical, + weather_timer:connect_signal("timeout", function () + local resp_json = {} + local res, status = http.request{ + url=weather_api_url, + sink=ltn12.sink.table(resp_json), + -- ref: + -- http://w3.impa.br/~diego/software/luasocket/old/luasocket-2.0/http.html + create=function() + -- ref: https://stackoverflow.com/a/6021774/595220 + local req_sock = socket.tcp() + -- 't' — overall timeout + req_sock:settimeout(0.2, 't') + -- 'b' — block timeout + req_sock:settimeout(0.001, 'b') + return req_sock + end } - elseif (resp_json ~= nil and resp_json ~= '') then - resp = json.decode(resp_json) - icon_widget.image = path_to_icons .. icon_map[resp.weather[1].icon] - temp_widget:set_text(gen_temperature_str(resp.main.temp, '%.0f', - secrets.weather_both_temp_units_widget)) - end -end) -weather_timer:start() -weather_timer:emit_signal("timeout") - ---- Notification with weather information. Popups when mouse hovers over the icon -local notification -weather_widget:connect_signal("mouse::enter", function() - notification = naughty.notify{ - icon = path_to_icons .. icon_map[resp.weather[1].icon], - icon_size=20, - text = - '<big>' .. resp.weather[1].main .. ' (' .. resp.weather[1].description .. ')</big><br>' .. - '<b>Humidity:</b> ' .. resp.main.humidity .. '%<br>' .. - '<b>Temperature:</b> ' .. gen_temperature_str(resp.main.temp, '%.1f', - secrets.weather_both_temp_units_popup) .. '<br>' .. - '<b>Pressure:</b> ' .. resp.main.pressure .. 'hPa<br>' .. - '<b>Clouds:</b> ' .. resp.clouds.all .. '%<br>' .. - '<b>Wind:</b> ' .. resp.wind.speed .. 'm/s (' .. to_direction(resp.wind.deg) .. ')', - timeout = 5, hover_timeout = 10, - width = (secrets.weather_both_temp_units_popup == true and 210 or 200) - } -end) + if (resp_json ~= nil) then + resp_json = table.concat(resp_json) + end + + if (status ~= 200 and resp_json ~= nil and resp_json ~= '') then + local err_resp = json.decode(resp_json) + naughty.notify{ + title = 'Weather Widget Error', + text = err_resp.message, + preset = naughty.config.presets.critical, + } + elseif (resp_json ~= nil and resp_json ~= '') then + resp = json.decode(resp_json) + icon_widget.image = path_to_icons .. icon_map[resp.weather[1].icon] + temp_widget:set_text(gen_temperature_str(resp.main.temp, '%.0f', both_units_widget)) + end + end) + weather_timer:start() + weather_timer:emit_signal("timeout") + + --- Notification with weather information. Popups when mouse hovers over the icon + local notification + weather_widget:connect_signal("mouse::enter", function() + notification = naughty.notify{ + icon = path_to_icons .. icon_map[resp.weather[1].icon], + icon_size=20, + text = + '<big>' .. resp.weather[1].main .. ' (' .. resp.weather[1].description .. ')</big><br>' .. + '<b>Humidity:</b> ' .. resp.main.humidity .. '%<br>' .. + '<b>Temperature:</b> ' .. gen_temperature_str(resp.main.temp, '%.1f', + both_units_popup) .. '<br>' .. + '<b>Pressure:</b> ' .. resp.main.pressure .. 'hPa<br>' .. + '<b>Clouds:</b> ' .. resp.clouds.all .. '%<br>' .. + '<b>Wind:</b> ' .. resp.wind.speed .. 'm/s (' .. to_direction(resp.wind.deg) .. ')', + timeout = 5, hover_timeout = 10, + width = (both_units_popup == true and 210 or 200) + } + end) + + weather_widget:connect_signal("mouse::leave", function() + naughty.destroy(notification) + end) -weather_widget:connect_signal("mouse::leave", function() - naughty.destroy(notification) -end) + return weather_widget +end -return weather_widget +return setmetatable(weather_widget, { __call = function(_, ...) + return worker(...) +end }) |