diff --git a/weather-widget/README.md b/weather-widget/README.md index 730c1f5..defe1b7 100644 --- a/weather-widget/README.md +++ b/weather-widget/README.md @@ -1,8 +1,13 @@ # Weather widget -![Weather Widget](./weather-widget.png) +

+ screenshot +

-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. +Widget consists of three sections: + - current weather, including humidity, wind speed, UV index + - hourly forecast for the next 24 hours + - daily forecast for the next five days ## Customization @@ -10,34 +15,63 @@ It is possible to customize widget by providing a table with all or some of the | 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 | -| `notification_position` | `top_right` | The notification position | +| coordinates | Required | Table with two elements: latitude and longitude, e.g. `{46.204400, 6.143200}` | +| api_key | Required | Get it [here](https://openweathermap.org/appid) | +| font_name | `beautiful.font:gsub("%s%d+$", "")` | **Name** of the font to use e.g. 'Play' | +| both_units_widget | false | Show temperature in both units - '28°C (83°F) | +| units | metric | `metric` for celsius, `imperial` for fahrenheit | +| show_hourly_forecast | false | Show hourly forecase section | +| time_format_12h |false | 12 or 24 hour format (13:00 - default or 1pm) | +| show_daily_forecast | false | Show daily forecast section | +| 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 | `.svg` | File extension of icons in the pack | -### Example: +### Icons: + +Widget comes with two predefined icon packs: + + - weather-underground-icons taken from [here](https://github.com/manifestinteractive/weather-underground-icons) + - VitalyGorbachev taken from [here](https://www.flaticon.com/authors/vitaly-gorbachev) + +To add your custom icons, create a folder with the pack name under `/icons` and use the folder name in widget's config. There should be 18 icons, preferably 128x128 minimum. Icons should also respect the naming convention, please check widget's source. + +### Examples: + + +#### Custom font, icons + +![example1](./screenshots/example1.png) ```lua -weather_widget({ - api_key = 'your-api-key', +weather_curl_widget({ + api_key='', + coordinates = {45.5017, -73.5673}, + time_format_12h = true, units = 'imperial', - font = 'Ubuntu Mono 9' + both_units_widget = true, + font_name = 'Carter One', + icons = 'VitalyGorbachev', + show_hourly_forecast = true, + show_daily_forecast = true, +}), +``` + +#### Only current weather + +![example2](./screenshots/example2.png) + +```lua +weather_curl_widget({ + api_key='', + coordinates = {45.5017, -73.5673}, }), ``` + ## Installation -1. Install lua socket - to make HTTP calls to get the weather information. - - ```bash - $ sudo apt-get install lua-socket - ``` - 1. Download json parser for lua from [github.com/rxi/json.lua](https://github.com/rxi/json.lua) and place it under **~/.config/awesome/** (don't forget to star a repo ): ```bash @@ -66,15 +100,27 @@ weather_widget({ layout = wibox.layout.fixed.horizontal, ... --default - weather_widget({api_key = 'your-api-key'}), - --customized weather_widget({ - api_key = 'your-api-key', + coordinates = {45.5017, -73.5673}, + api_key='c3d7320b359da4e48c2d682a04076576', + }), + , + --customized + weather_curl_widget({ + api_key='', + coordinates = {45.5017, -73.5673}, + time_format_12h = true, units = 'imperial', - font = 'Ubuntu Mono 9' - }) + both_units_widget = true, + font_name = 'Carter One', + icons = 'VitalyGorbachev', + show_hourly_forecast = true, + show_daily_forecast = true, + }), ... ``` -You can read how it works in more details [here](http://pavelmakhov.com/2017/02/weather-widget-for-awesome-wm) +## How it works + +TBW \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/broken-clouds-night.svg b/weather-widget/icons/VitalyGorbachev/broken-clouds-night.svg new file mode 100644 index 0000000..8b7fc48 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/broken-clouds-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/broken-clouds.svg b/weather-widget/icons/VitalyGorbachev/broken-clouds.svg new file mode 100644 index 0000000..d42ea59 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/broken-clouds.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/clear-sky-night.svg b/weather-widget/icons/VitalyGorbachev/clear-sky-night.svg new file mode 100644 index 0000000..44f096c --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/clear-sky-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/clear-sky.svg b/weather-widget/icons/VitalyGorbachev/clear-sky.svg new file mode 100644 index 0000000..dc82163 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/clear-sky.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/few-clouds-night.svg b/weather-widget/icons/VitalyGorbachev/few-clouds-night.svg new file mode 100644 index 0000000..8b7fc48 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/few-clouds-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/few-clouds.svg b/weather-widget/icons/VitalyGorbachev/few-clouds.svg new file mode 100644 index 0000000..d42ea59 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/few-clouds.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/mist-night.svg b/weather-widget/icons/VitalyGorbachev/mist-night.svg new file mode 100644 index 0000000..960b07d --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/mist-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/mist.svg b/weather-widget/icons/VitalyGorbachev/mist.svg new file mode 100644 index 0000000..770f8d7 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/mist.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/rain-night.svg b/weather-widget/icons/VitalyGorbachev/rain-night.svg new file mode 100644 index 0000000..11ecf00 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/rain-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/rain.svg b/weather-widget/icons/VitalyGorbachev/rain.svg new file mode 100644 index 0000000..11ecf00 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/rain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/scattered-clouds-night.svg b/weather-widget/icons/VitalyGorbachev/scattered-clouds-night.svg new file mode 100644 index 0000000..8b7fc48 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/scattered-clouds-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/scattered-clouds.svg b/weather-widget/icons/VitalyGorbachev/scattered-clouds.svg new file mode 100644 index 0000000..d42ea59 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/scattered-clouds.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/shower-rain-night.svg b/weather-widget/icons/VitalyGorbachev/shower-rain-night.svg new file mode 100644 index 0000000..4d1897c --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/shower-rain-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/shower-rain.svg b/weather-widget/icons/VitalyGorbachev/shower-rain.svg new file mode 100644 index 0000000..4d1897c --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/shower-rain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/snow-night.svg b/weather-widget/icons/VitalyGorbachev/snow-night.svg new file mode 100644 index 0000000..bee891e --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/snow-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/snow.svg b/weather-widget/icons/VitalyGorbachev/snow.svg new file mode 100644 index 0000000..e2ea140 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/snow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/thunderstorm-night.svg b/weather-widget/icons/VitalyGorbachev/thunderstorm-night.svg new file mode 100644 index 0000000..1813197 --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/thunderstorm-night.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/VitalyGorbachev/thunderstorm.svg b/weather-widget/icons/VitalyGorbachev/thunderstorm.svg new file mode 100644 index 0000000..44a733c --- /dev/null +++ b/weather-widget/icons/VitalyGorbachev/thunderstorm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/weather-widget/icons/weather-underground-icons/broken-clouds-night.png b/weather-widget/icons/weather-underground-icons/broken-clouds-night.png new file mode 100644 index 0000000..061d1cd Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/broken-clouds-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/broken-clouds.png b/weather-widget/icons/weather-underground-icons/broken-clouds.png new file mode 100755 index 0000000..5967d92 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/broken-clouds.png differ diff --git a/weather-widget/icons/weather-underground-icons/clear-sky-night.png b/weather-widget/icons/weather-underground-icons/clear-sky-night.png new file mode 100644 index 0000000..cc40d0f Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/clear-sky-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/clear-sky.png b/weather-widget/icons/weather-underground-icons/clear-sky.png new file mode 100755 index 0000000..acf8e5c Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/clear-sky.png differ diff --git a/weather-widget/icons/weather-underground-icons/few-clouds-night.png b/weather-widget/icons/weather-underground-icons/few-clouds-night.png new file mode 100644 index 0000000..9c34fab Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/few-clouds-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/few-clouds.png b/weather-widget/icons/weather-underground-icons/few-clouds.png new file mode 100755 index 0000000..7580fc5 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/few-clouds.png differ diff --git a/weather-widget/icons/weather-underground-icons/mist-night.png b/weather-widget/icons/weather-underground-icons/mist-night.png new file mode 100755 index 0000000..102142a Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/mist-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/mist.png b/weather-widget/icons/weather-underground-icons/mist.png new file mode 100755 index 0000000..102142a Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/mist.png differ diff --git a/weather-widget/icons/weather-underground-icons/rain-night.png b/weather-widget/icons/weather-underground-icons/rain-night.png new file mode 100755 index 0000000..49f0903 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/rain-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/rain.png b/weather-widget/icons/weather-underground-icons/rain.png new file mode 100755 index 0000000..49f0903 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/rain.png differ diff --git a/weather-widget/icons/weather-underground-icons/scattered-clouds-night.png b/weather-widget/icons/weather-underground-icons/scattered-clouds-night.png new file mode 100755 index 0000000..63cb1b2 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/scattered-clouds-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/scattered-clouds.png b/weather-widget/icons/weather-underground-icons/scattered-clouds.png new file mode 100755 index 0000000..63cb1b2 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/scattered-clouds.png differ diff --git a/weather-widget/icons/weather-underground-icons/shower-rain-night.png b/weather-widget/icons/weather-underground-icons/shower-rain-night.png new file mode 100755 index 0000000..49f0903 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/shower-rain-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/shower-rain.png b/weather-widget/icons/weather-underground-icons/shower-rain.png new file mode 100755 index 0000000..49f0903 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/shower-rain.png differ diff --git a/weather-widget/icons/weather-underground-icons/snow-night.png b/weather-widget/icons/weather-underground-icons/snow-night.png new file mode 100755 index 0000000..0a7f006 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/snow-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/snow.png b/weather-widget/icons/weather-underground-icons/snow.png new file mode 100755 index 0000000..0a7f006 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/snow.png differ diff --git a/weather-widget/icons/weather-underground-icons/thunderstorm-night.png b/weather-widget/icons/weather-underground-icons/thunderstorm-night.png new file mode 100755 index 0000000..2102104 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/thunderstorm-night.png differ diff --git a/weather-widget/icons/weather-underground-icons/thunderstorm.png b/weather-widget/icons/weather-underground-icons/thunderstorm.png new file mode 100755 index 0000000..2102104 Binary files /dev/null and b/weather-widget/icons/weather-underground-icons/thunderstorm.png differ diff --git a/weather-widget/screenshots/example1.png b/weather-widget/screenshots/example1.png new file mode 100644 index 0000000..7074faa Binary files /dev/null and b/weather-widget/screenshots/example1.png differ diff --git a/weather-widget/screenshots/example2.png b/weather-widget/screenshots/example2.png new file mode 100644 index 0000000..857274b Binary files /dev/null and b/weather-widget/screenshots/example2.png differ diff --git a/weather-widget/screenshots/weather-widget.png b/weather-widget/screenshots/weather-widget.png new file mode 100644 index 0000000..c7fc37e Binary files /dev/null and b/weather-widget/screenshots/weather-widget.png differ diff --git a/weather-widget/weather.json b/weather-widget/weather.json new file mode 100644 index 0000000..4a18714 --- /dev/null +++ b/weather-widget/weather.json @@ -0,0 +1,1224 @@ +{ + "lat": 33.44, + "lon": -94.04, + "timezone": "America/Chicago", + "timezone_offset": -18000, + "current": { + "dt": 1594490161, + "sunrise": 1594466108, + "sunset": 1594517275, + "temp": 32.69, + "feels_like": 36.81, + "pressure": 1017, + "humidity": 59, + "dew_point": 23.63, + "uvi": 7.94, + "clouds": 40, + "visibility": 16093, + "wind_speed": 2.1, + "wind_deg": 250, + "weather": [ + { + "id": 802, + "main": "Clear Sky", + "description": "clear sky", + "icon": "01d" + } + ] + }, + "hourly": [ + { + "dt": 1594486800, + "temp": 32.69, + "feels_like": 36.4, + "pressure": 1017, + "humidity": 59, + "dew_point": 23.63, + "clouds": 40, + "wind_speed": 2.68, + "wind_deg": 242, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ] + }, + { + "dt": 1594490400, + "temp": 33.38, + "feels_like": 37.27, + "pressure": 1017, + "humidity": 59, + "dew_point": 24.27, + "clouds": 21, + "wind_speed": 2.97, + "wind_deg": 248, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02d" + } + ] + }, + { + "dt": 1594494000, + "temp": 34.44, + "feels_like": 38.38, + "pressure": 1015, + "humidity": 55, + "dew_point": 24.09, + "clouds": 28, + "wind_speed": 2.74, + "wind_deg": 254, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ] + }, + { + "dt": 1594497600, + "temp": 35.32, + "feels_like": 39.58, + "pressure": 1014, + "humidity": 53, + "dew_point": 24.28, + "clouds": 18, + "wind_speed": 2.45, + "wind_deg": 260, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02d" + } + ] + }, + { + "dt": 1594501200, + "temp": 35.57, + "feels_like": 39.73, + "pressure": 1013, + "humidity": 52, + "dew_point": 24.19, + "clouds": 16, + "wind_speed": 2.52, + "wind_deg": 259, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02d" + } + ] + }, + { + "dt": 1594504800, + "temp": 35.34, + "feels_like": 39.82, + "pressure": 1012, + "humidity": 55, + "dew_point": 25.07, + "clouds": 13, + "wind_speed": 2.68, + "wind_deg": 256, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02d" + } + ] + }, + { + "dt": 1594508400, + "temp": 34.85, + "feels_like": 40.34, + "pressure": 1012, + "humidity": 61, + "dew_point": 26.36, + "clouds": 10, + "wind_speed": 2.42, + "wind_deg": 249, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594512000, + "temp": 33.39, + "feels_like": 39.08, + "pressure": 1012, + "humidity": 67, + "dew_point": 26.53, + "clouds": 9, + "wind_speed": 2.34, + "wind_deg": 246, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594515600, + "temp": 30.82, + "feels_like": 35.85, + "pressure": 1012, + "humidity": 73, + "dew_point": 25.61, + "clouds": 0, + "wind_speed": 2.35, + "wind_deg": 240, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594519200, + "temp": 29.56, + "feels_like": 33.64, + "pressure": 1012, + "humidity": 73, + "dew_point": 24.34, + "clouds": 0, + "wind_speed": 2.65, + "wind_deg": 227, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594522800, + "temp": 28.72, + "feels_like": 32.55, + "pressure": 1012, + "humidity": 75, + "dew_point": 23.97, + "clouds": 0, + "wind_speed": 2.7, + "wind_deg": 223, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594526400, + "temp": 27.79, + "feels_like": 31.42, + "pressure": 1012, + "humidity": 77, + "dew_point": 23.56, + "clouds": 0, + "wind_speed": 2.61, + "wind_deg": 211, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594530000, + "temp": 27.27, + "feels_like": 30.91, + "pressure": 1012, + "humidity": 79, + "dew_point": 23.39, + "clouds": 0, + "wind_speed": 2.54, + "wind_deg": 226, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594533600, + "temp": 27.17, + "feels_like": 30.72, + "pressure": 1012, + "humidity": 79, + "dew_point": 23.23, + "clouds": 0, + "wind_speed": 2.58, + "wind_deg": 213, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594537200, + "temp": 26.91, + "feels_like": 30.06, + "pressure": 1012, + "humidity": 78, + "dew_point": 22.95, + "clouds": 0, + "wind_speed": 2.79, + "wind_deg": 225, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594540800, + "temp": 26.57, + "feels_like": 29.76, + "pressure": 1011, + "humidity": 79, + "dew_point": 22.68, + "clouds": 33, + "wind_speed": 2.63, + "wind_deg": 217, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03n" + } + ] + }, + { + "dt": 1594544400, + "temp": 26.39, + "feels_like": 28.98, + "pressure": 1011, + "humidity": 78, + "dew_point": 22.36, + "clouds": 56, + "wind_speed": 3.19, + "wind_deg": 191, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ] + }, + { + "dt": 1594548000, + "temp": 25.97, + "feels_like": 29.15, + "pressure": 1011, + "humidity": 79, + "dew_point": 22.12, + "clouds": 67, + "wind_speed": 2.2, + "wind_deg": 211, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ] + }, + { + "dt": 1594551600, + "temp": 25.6, + "feels_like": 28.65, + "pressure": 1012, + "humidity": 79, + "dew_point": 21.77, + "clouds": 72, + "wind_speed": 2.12, + "wind_deg": 257, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04n" + } + ] + }, + { + "dt": 1594555200, + "temp": 25.25, + "feels_like": 29.31, + "pressure": 1012, + "humidity": 84, + "dew_point": 22.42, + "clouds": 74, + "wind_speed": 1.18, + "wind_deg": 276, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10d" + } + ], + "rain": { + "1h": 0.66 + } + }, + { + "dt": 1594558800, + "temp": 26.51, + "feels_like": 31.02, + "pressure": 1013, + "humidity": 82, + "dew_point": 23.22, + "clouds": 91, + "wind_speed": 1.19, + "wind_deg": 227, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10d" + } + ], + "rain": { + "1h": 0.5 + } + }, + { + "dt": 1594562400, + "temp": 27.99, + "feels_like": 31.34, + "pressure": 1012, + "humidity": 75, + "dew_point": 23.26, + "clouds": 87, + "wind_speed": 2.82, + "wind_deg": 223, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ] + }, + { + "dt": 1594566000, + "temp": 29.6, + "feels_like": 32.28, + "pressure": 1012, + "humidity": 67, + "dew_point": 23.02, + "clouds": 63, + "wind_speed": 3.51, + "wind_deg": 236, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ] + }, + { + "dt": 1594569600, + "temp": 31.12, + "feels_like": 33.49, + "pressure": 1011, + "humidity": 62, + "dew_point": 23.22, + "clouds": 52, + "wind_speed": 4.08, + "wind_deg": 239, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ] + }, + { + "dt": 1594573200, + "temp": 32.66, + "feels_like": 35.05, + "pressure": 1011, + "humidity": 58, + "dew_point": 23.6, + "clouds": 46, + "wind_speed": 4.31, + "wind_deg": 238, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ] + }, + { + "dt": 1594576800, + "temp": 34.15, + "feels_like": 36.59, + "pressure": 1011, + "humidity": 54, + "dew_point": 23.74, + "clouds": 40, + "wind_speed": 4.4, + "wind_deg": 236, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ] + }, + { + "dt": 1594580400, + "temp": 35.24, + "feels_like": 37.8, + "pressure": 1010, + "humidity": 51, + "dew_point": 23.83, + "clouds": 0, + "wind_speed": 4.27, + "wind_deg": 246, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594584000, + "temp": 35.73, + "feels_like": 38.39, + "pressure": 1009, + "humidity": 50, + "dew_point": 23.92, + "clouds": 0, + "wind_speed": 4.23, + "wind_deg": 262, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594587600, + "temp": 35.89, + "feels_like": 38.87, + "pressure": 1008, + "humidity": 51, + "dew_point": 24.29, + "clouds": 0, + "wind_speed": 4.17, + "wind_deg": 267, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594591200, + "temp": 35.63, + "feels_like": 39.46, + "pressure": 1008, + "humidity": 55, + "dew_point": 25.31, + "clouds": 0, + "wind_speed": 3.85, + "wind_deg": 266, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594594800, + "temp": 35, + "feels_like": 39.97, + "pressure": 1007, + "humidity": 61, + "dew_point": 26.37, + "clouds": 0, + "wind_speed": 3.3, + "wind_deg": 262, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594598400, + "temp": 33.25, + "feels_like": 38.23, + "pressure": 1007, + "humidity": 66, + "dew_point": 26.08, + "clouds": 0, + "wind_speed": 2.98, + "wind_deg": 259, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594602000, + "temp": 30.86, + "feels_like": 35.71, + "pressure": 1008, + "humidity": 72, + "dew_point": 25.37, + "clouds": 0, + "wind_speed": 2.44, + "wind_deg": 254, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ] + }, + { + "dt": 1594605600, + "temp": 29.71, + "feels_like": 34.14, + "pressure": 1008, + "humidity": 72, + "dew_point": 24.24, + "clouds": 0, + "wind_speed": 2.07, + "wind_deg": 246, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594609200, + "temp": 29.09, + "feels_like": 33.6, + "pressure": 1009, + "humidity": 73, + "dew_point": 23.92, + "clouds": 0, + "wind_speed": 1.65, + "wind_deg": 239, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594612800, + "temp": 28.41, + "feels_like": 33.33, + "pressure": 1009, + "humidity": 75, + "dew_point": 23.77, + "clouds": 0, + "wind_speed": 0.9, + "wind_deg": 301, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594616400, + "temp": 27.65, + "feels_like": 31.94, + "pressure": 1010, + "humidity": 79, + "dew_point": 23.7, + "clouds": 0, + "wind_speed": 1.9, + "wind_deg": 342, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594620000, + "temp": 26.81, + "feels_like": 30.18, + "pressure": 1010, + "humidity": 78, + "dew_point": 22.81, + "clouds": 0, + "wind_speed": 2.39, + "wind_deg": 13, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594623600, + "temp": 25.86, + "feels_like": 28.37, + "pressure": 1010, + "humidity": 75, + "dew_point": 21.3, + "clouds": 0, + "wind_speed": 2.45, + "wind_deg": 41, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594627200, + "temp": 24.94, + "feels_like": 26.96, + "pressure": 1010, + "humidity": 75, + "dew_point": 20.36, + "clouds": 0, + "wind_speed": 2.53, + "wind_deg": 49, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594630800, + "temp": 23.94, + "feels_like": 25.44, + "pressure": 1010, + "humidity": 78, + "dew_point": 19.9, + "clouds": 2, + "wind_speed": 3.05, + "wind_deg": 56, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01n" + } + ] + }, + { + "dt": 1594634400, + "temp": 23.22, + "feels_like": 25.05, + "pressure": 1011, + "humidity": 81, + "dew_point": 19.94, + "clouds": 14, + "wind_speed": 2.51, + "wind_deg": 65, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02n" + } + ] + }, + { + "dt": 1594638000, + "temp": 22.87, + "feels_like": 24.56, + "pressure": 1011, + "humidity": 81, + "dew_point": 19.61, + "clouds": 17, + "wind_speed": 2.48, + "wind_deg": 74, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02n" + } + ] + }, + { + "dt": 1594641600, + "temp": 22.82, + "feels_like": 24.7, + "pressure": 1012, + "humidity": 83, + "dew_point": 19.8, + "clouds": 29, + "wind_speed": 2.44, + "wind_deg": 63, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ] + }, + { + "dt": 1594645200, + "temp": 23.84, + "feels_like": 25.88, + "pressure": 1013, + "humidity": 80, + "dew_point": 20.21, + "clouds": 100, + "wind_speed": 2.48, + "wind_deg": 62, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ] + }, + { + "dt": 1594648800, + "temp": 25, + "feels_like": 27, + "pressure": 1013, + "humidity": 75, + "dew_point": 20.37, + "clouds": 100, + "wind_speed": 2.59, + "wind_deg": 67, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ] + }, + { + "dt": 1594652400, + "temp": 26.18, + "feels_like": 27.69, + "pressure": 1012, + "humidity": 73, + "dew_point": 21.06, + "clouds": 100, + "wind_speed": 3.79, + "wind_deg": 101, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ] + }, + { + "dt": 1594656000, + "temp": 28.36, + "feels_like": 30.56, + "pressure": 1012, + "humidity": 69, + "dew_point": 22.32, + "clouds": 83, + "wind_speed": 3.66, + "wind_deg": 128, + "weather": [ + { + "id": 803, + "main": "Clouds", + "description": "broken clouds", + "icon": "04d" + } + ] + } + ], + "daily": [ + { + "dt": 1594490400, + "sunrise": 1594466108, + "sunset": 1594517275, + "temp": { + "day": 33.38, + "min": 27.17, + "max": 34.96, + "night": 27.17, + "eve": 33.35, + "morn": 32.69 + }, + "feels_like": { + "day": 37.27, + "night": 30.72, + "eve": 39.01, + "morn": 36.67 + }, + "pressure": 1017, + "humidity": 59, + "dew_point": 24.27, + "wind_speed": 2.97, + "wind_deg": 248, + "weather": [ + { + "id": 801, + "main": "Clouds", + "description": "few clouds", + "icon": "02d" + } + ], + "clouds": 21, + "uvi": 11.94 + }, + { + "dt": 1594576800, + "sunrise": 1594552543, + "sunset": 1594603655, + "temp": { + "day": 34.15, + "min": 25.25, + "max": 35.89, + "night": 26.81, + "eve": 33.25, + "morn": 25.25 + }, + "feels_like": { + "day": 36.59, + "night": 30.18, + "eve": 38.23, + "morn": 29.31 + }, + "pressure": 1011, + "humidity": 54, + "dew_point": 23.74, + "wind_speed": 4.4, + "wind_deg": 236, + "weather": [ + { + "id": 500, + "main": "Rain", + "description": "light rain", + "icon": "10d" + } + ], + "clouds": 40, + "rain": 1.16, + "uvi": 11.61 + }, + { + "dt": 1594663200, + "sunrise": 1594638978, + "sunset": 1594690034, + "temp": { + "day": 29.22, + "min": 22.82, + "max": 29.22, + "night": 26.71, + "eve": 28.98, + "morn": 22.82 + }, + "feels_like": { + "day": 34.31, + "night": 28.82, + "eve": 34.45, + "morn": 24.7 + }, + "pressure": 1012, + "humidity": 72, + "dew_point": 23.66, + "wind_speed": 0.74, + "wind_deg": 287, + "weather": [ + { + "id": 804, + "main": "Clouds", + "description": "overcast clouds", + "icon": "04d" + } + ], + "clouds": 85, + "uvi": 12.72 + }, + { + "dt": 1594749600, + "sunrise": 1594725414, + "sunset": 1594776411, + "temp": { + "day": 33.67, + "min": 24.06, + "max": 35.68, + "night": 25.94, + "eve": 32.24, + "morn": 24.06 + }, + "feels_like": { + "day": 35.84, + "night": 27.78, + "eve": 35.66, + "morn": 27.28 + }, + "pressure": 1012, + "humidity": 50, + "dew_point": 21.95, + "wind_speed": 3.45, + "wind_deg": 183, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ], + "clouds": 9, + "uvi": 11.67 + }, + { + "dt": 1594836000, + "sunrise": 1594811851, + "sunset": 1594862786, + "temp": { + "day": 32.79, + "min": 24.61, + "max": 35.24, + "night": 26.42, + "eve": 31.72, + "morn": 24.61 + }, + "feels_like": { + "day": 34.67, + "night": 28.57, + "eve": 35.11, + "morn": 27.47 + }, + "pressure": 1014, + "humidity": 53, + "dew_point": 22.04, + "wind_speed": 3.97, + "wind_deg": 208, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ], + "clouds": 35, + "uvi": 11.55 + }, + { + "dt": 1594922400, + "sunrise": 1594898288, + "sunset": 1594949160, + "temp": { + "day": 33.89, + "min": 24.07, + "max": 35.5, + "night": 26.61, + "eve": 32.58, + "morn": 24.07 + }, + "feels_like": { + "day": 35.74, + "night": 29.39, + "eve": 36.52, + "morn": 27.33 + }, + "pressure": 1015, + "humidity": 49, + "dew_point": 22.01, + "wind_speed": 3.81, + "wind_deg": 225, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ], + "clouds": 29, + "uvi": 11.67 + }, + { + "dt": 1595008800, + "sunrise": 1594984726, + "sunset": 1595035532, + "temp": { + "day": 34.95, + "min": 24.45, + "max": 36.42, + "night": 26.97, + "eve": 33.81, + "morn": 24.45 + }, + "feels_like": { + "day": 38.11, + "night": 29.69, + "eve": 38.22, + "morn": 26.84 + }, + "pressure": 1016, + "humidity": 50, + "dew_point": 23.17, + "wind_speed": 2.94, + "wind_deg": 230, + "weather": [ + { + "id": 802, + "main": "Clouds", + "description": "scattered clouds", + "icon": "03d" + } + ], + "clouds": 46, + "uvi": 11.86 + }, + { + "dt": 1595095200, + "sunrise": 1595071164, + "sunset": 1595121903, + "temp": { + "day": 35.47, + "min": 24.4, + "max": 37.04, + "night": 28.18, + "eve": 34.23, + "morn": 24.4 + }, + "feels_like": { + "day": 38.15, + "night": 30.61, + "eve": 38.67, + "morn": 26.95 + }, + "pressure": 1015, + "humidity": 46, + "dew_point": 22.36, + "wind_speed": 2.93, + "wind_deg": 238, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ], + "clouds": 2, + "uvi": 11.67 + } + ] +} \ No newline at end of file diff --git a/weather-widget/weather.lua b/weather-widget/weather.lua index 5aaf426..4fcdba7 100644 --- a/weather-widget/weather.lua +++ b/weather-widget/weather.lua @@ -3,225 +3,456 @@ -- https://openweathermap.org/ -- -- @author Pavel Makhov --- @copyright 2018 Pavel Makhov +-- @copyright 2020 Pavel Makhov ------------------------------------------------- - -local socket = require("socket") -local http = require("socket.http") -local ltn12 = require("ltn12") +local awful = require("awful") +local watch = require("awful.widget.watch") local json = require("json") local naughty = require("naughty") local wibox = require("wibox") local gears = require("gears") +local beautiful = require("beautiful") -local path_to_icons = "/usr/share/icons/Arc/status/symbolic/" +local HOME_DIR = os.getenv("HOME") +local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/weather-widget' +local GET_FORECAST_CMD = [[bash -c "curl -s --show-error -X GET '%s'"]] + +local function show_warning(message) + naughty.notify { + preset = naughty.config.presets.critical, + title = 'Weather Widget', + text = message + } +end local weather_widget = {} +local warning_shown = false +local notification +local tooltip = awful.tooltip { + mode = 'outside', + preferred_positions = {'bottom'} +} + +local weather_popup = awful.popup { + ontop = true, + visible = false, + shape = gears.shape.rounded_rect, + border_width = 1, + border_color = beautiful.bg_focus, + maximum_width = 400, + offset = {y = 5}, + widget = {} +} + +--- Maps openWeatherMap icon name to file name w/o extension +local icon_map = { + ["01d"] = "clear-sky", + ["02d"] = "few-clouds", + ["03d"] = "scattered-clouds", + ["04d"] = "broken-clouds", + ["09d"] = "shower-rain", + ["10d"] = "rain", + ["11d"] = "thunderstorm", + ["13d"] = "snow", + ["50d"] = "mist", + ["01n"] = "clear-sky-night", + ["02n"] = "few-clouds-night", + ["03n"] = "scattered-clouds-night", + ["04n"] = "broken-clouds-night", + ["09n"] = "shower-rain-night", + ["10n"] = "rain-night", + ["11n"] = "thunderstorm-night", + ["13n"] = "snow-night", + ["50n"] = "mist-night" +} + +--- 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 + +--- 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 + +local function gen_temperature_str(temp, fmt_str, show_other_units, 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 + return s +end + +local function uvi_index_color(uvi) + local color + if uvi >= 0 and uvi < 3 then color = '#A3BE8C' + elseif uvi >= 3 and uvi < 6 then color = '#EBCB8B' + elseif uvi >= 6 and uvi < 8 then color = '#D08770' + elseif uvi >= 8 and uvi < 11 then color = '#BF616A' + elseif uvi >= 11 then color = '#B48EAD' + end + + return '' .. uvi .. '' +end 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'} + --- Validate required parameters + if args.coordinates == nil or args.api_key == nil then + show_warning('Required parameters are not set: ' .. + (args.coordinates == nil and 'coordinates' or '') .. + (args.api_key == nil and ', api_key ' or '')) + return + end + + local coordinates = args.coordinates + 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 both_units_popup = args.both_units_popup or false - local position = args.notification_position or "top_right" + local show_hourly_forecast = args.show_hourly_forecast + local show_daily_forecast = args.show_daily_forecast + local icon_pack_name = args.icons or 'weather-underground-icons' + local icons_extension = args.icons_extension or '.png' - 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, - } - - local temp_widget = wibox.widget { - font = font, - widget = wibox.widget.textbox, - } + local owm_one_cal_api = + ('https://api.openweathermap.org/data/2.5/onecall' .. + '?lat=' .. coordinates[1] .. '&lon=' .. coordinates[2] .. '&appid=' .. api_key .. + '&units=' .. units .. '&exclude=minutely' .. + (show_hourly_forecast == false and ',hourly' or '') .. + (show_daily_forecast == false and ',daily' or '')) weather_widget = wibox.widget { - icon_widget, - temp_widget, + { + { + id = 'icon', + resize = true, + widget = wibox.widget.imagebox + }, + valign = 'center', + widget = wibox.container.place, + }, + { + id = 'txt', + widget = wibox.widget.textbox + }, 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", - } - 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 - - -- Convert degrees Fahrenheit to Celsius - local function fahrenheit_to_celsius(f) - return (f-32)*5/9 - end - - 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' + set_image = function(self, path) + self:get_children_by_id('icon')[1].image = path + end, + set_text = function(self, text) + self:get_children_by_id('txt')[1].text = text + end, + is_ok = function(self, is_ok) + if is_ok then + self:get_children_by_id('icon')[1]:set_opacity(1) + self:get_children_by_id('icon')[1]:emit_signal('widget:redraw_needed') else - temp_conv = fahrenheit_to_celsius(temp) - units_conv = 'C' + self:get_children_by_id('icon')[1]:set_opacity(0.2) + self:get_children_by_id('icon')[1]:emit_signal('widget:redraw_needed') end - - local temp_conv_str = string.format(fmt_str, temp_conv) - s = s .. ' ' .. '('.. temp_conv_str .. '°' .. units_conv .. ')' end - return s - end + } - local function error_display(resp_json) - weather_timer.timeout = math.min(15 * 60, weather_timer.timeout * 2) - weather_timer:again() - local err_resp = json.decode(resp_json) - naughty.notify{ - title = 'Weather Widget Error', - text = err_resp.message, - preset = naughty.config.presets.critical, - } - 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 - end - } - if (resp_json ~= nil) then - resp_json = table.concat(resp_json) + local current_weather_widget = wibox.widget { + { + { + { + id = 'icon', + resize = true, + forced_width = 128, + forced_height = 128, + widget = wibox.widget.imagebox + }, + align = 'center', + widget = wibox.container.place + }, + { + id = 'description', + font = font_name .. ' 10', + align = 'center', + widget = wibox.widget.textbox + }, + forced_width = 128, + layout = wibox.layout.align.vertical + }, + { + { + { + id = 'temp', + font = font_name .. ' 48', + widget = wibox.widget.textbox + }, + { + id = 'feels_like_temp', + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.vertical + }, + { + { + id = 'wind', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + id = 'humidity', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + id = 'uv', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + expand = 'inside', + layout = wibox.layout.align.vertical + }, + spacing = 16, + forced_width = 150, + layout = wibox.layout.fixed.vertical + }, + forced_width = 300, + layout = wibox.layout.flex.horizontal, + update = function(self, weather) + self:get_children_by_id('icon')[1]:set_image(WIDGET_DIR .. '/icons/' .. icon_pack_name .. '/' .. icon_map[weather.weather[1].icon] .. icons_extension) + self:get_children_by_id('temp')[1]:set_text(gen_temperature_str(weather.temp, '%.0f', false, units)) + self:get_children_by_id('feels_like_temp')[1]:set_text('Feels like ' .. gen_temperature_str(weather.feels_like, '%.0f', false, units)) + self:get_children_by_id('description')[1]:set_text(weather.weather[1].description) + self:get_children_by_id('wind')[1]:set_markup('Wind: ' .. weather.wind_speed .. 'm/s (' .. to_direction(weather.wind_deg) .. ')') + self:get_children_by_id('humidity')[1]:set_markup('Humidity: ' .. weather.humidity .. '%') + self:get_children_by_id('uv')[1]:set_markup('UV: ' .. uvi_index_color(weather.uvi)) end + } - if (status ~= 200 and resp_json ~= nil and resp_json ~= '') then - if (not pcall(error_display, resp_json)) then - naughty.notify{ - title = 'Weather Widget Error', - text = 'Cannot parse answer', - preset = naughty.config.presets.critical, + + local daily_forecast_widget = { + forced_width = 300, + layout = wibox.layout.flex.horizontal, + update = function(self, forecast, timezone_offset) + local count = #self + for i = 0, count do self[i]=nil end + for i, day in ipairs(forecast) do + if i > 5 then break end + local day_forecast = wibox.widget { + { + text = os.date('%a', tonumber(day.dt) + tonumber(timezone_offset)), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + { + { + image = WIDGET_DIR .. '/icons/' .. icon_pack_name .. '/' .. icon_map[day.weather[1].icon] .. icons_extension, + resize = true, + forced_width = 48, + forced_height = 48, + widget = wibox.widget.imagebox + }, + align = 'center', + layout = wibox.container.place + }, + { + text = day.weather[1].description, + font = font_name .. ' 8', + align = 'center', + forced_height = 50, + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.vertical + }, + { + { + text = gen_temperature_str(day.temp.day, '%.0f', false, units), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + { + text = gen_temperature_str(day.temp.night, '%.0f', false, units), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }, + layout = wibox.layout.fixed.vertical + }, + spacing = 8, + layout = wibox.layout.fixed.vertical } + table.insert(self, day_forecast) 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', both_units_widget)) - weather_timer.timeout = 60 - weather_timer:again() 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 = - '' .. resp.weather[1].main .. ' (' .. resp.weather[1].description .. ')
' .. - 'Humidity: ' .. resp.main.humidity .. '%
' .. - 'Temperature: ' .. gen_temperature_str(resp.main.temp, '%.1f', - both_units_popup) .. '
' .. - 'Pressure: ' .. resp.main.pressure .. 'hPa
' .. - 'Clouds: ' .. resp.clouds.all .. '%
' .. - 'Wind: ' .. resp.wind.speed .. 'm/s (' .. to_direction(resp.wind.deg) .. ')', - timeout = 5, hover_timeout = 10, - position = position, - screen = mouse.screen, - width = (both_units_popup == true and 210 or 200) + 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_widget = { + layout = wibox.layout.fixed.vertical, + update = function(self, hourly) + local hours_below = { + id = 'hours', + 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 = {} + for i, hour in ipairs(hourly) do + if i > 25 then break end + values[i] = hour.temp + if max_temp < hour.temp then max_temp = hour.temp end + if min_temp > hour.temp then min_temp = hour.temp 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.dt)), + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }) + table.insert(temp_below, wibox.widget { + markup = '' .. string.format('%.0f', hour.temp) .. '°' .. '', + align = 'center', + font = font_name .. ' 9', + widget = wibox.widget.textbox + }) + end + end + hourly_forecast_graph:set_max_value(max_temp) + hourly_forecast_graph:set_min_value(min_temp * 0.7) -- move graph a bit up + for i, value in ipairs(values) do + hourly_forecast_graph:add_value(value) + end + + local count = #self + for i = 0, count do self[i]=nil end + + + table.insert(self, temp_below) + 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) + end + } + + local function update_widget(widget, stdout, stderr) + if stderr ~= '' then + if not warning_shown then + show_warning(stderr) + warning_shown = true + widget:is_ok(false) + tooltip:add_to_object(widget) + + widget:connect_signal('mouse::enter', function() tooltip.text = stderr end) + end + return + end + + warning_shown = false + tooltip:remove_from_object(widget) + widget:is_ok(true) + + local result = json.decode(stdout) + + widget:set_image(WIDGET_DIR .. '/icons/' .. icon_pack_name .. '/' .. icon_map[result.current.weather[1].icon] .. icons_extension) + widget:set_text(gen_temperature_str(result.current.temp, '%.0f', both_units_widget, units)) + + current_weather_widget:update(result.current) + + local final_widget = { + current_weather_widget, + spacing = 16, + layout = wibox.layout.fixed.vertical } - end) - weather_widget:connect_signal("mouse::leave", function() - naughty.destroy(notification) - end) + if show_hourly_forecast then + hourly_forecast_widget:update(result.hourly) + table.insert(final_widget, hourly_forecast_widget) + end + + if show_daily_forecast then + daily_forecast_widget:update(result.daily, result.timezone_offset) + table.insert(final_widget, daily_forecast_widget) + end + + weather_popup:setup({ + { + final_widget, + margins = 10, + widget = wibox.container.margin + }, + bg = beautiful.bg_normal, + widget = wibox.container.background + }) + end + + weather_widget:buttons(awful.util.table.join(awful.button({}, 1, function() + if weather_popup.visible then + weather_popup.visible = not weather_popup.visible + else + weather_popup:move_next_to(mouse.current_widget_geometry) + end + end))) + + -- watch('cat /home/pmakhov/.config/awesome/awesome-wm-widgets/weather-widget/weather.json', 5, update_widget, weather_widget) + watch(string.format(GET_FORECAST_CMD, owm_one_cal_api), 5, update_widget, weather_widget) return weather_widget end -return setmetatable(weather_widget, { __call = function(_, ...) - return worker(...) -end }) +return setmetatable(weather_widget, {__call = function(_, ...) return worker(...) end})