Skip to content

Instantly share code, notes, and snippets.

@meskarune
Last active February 11, 2024 18:57
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save meskarune/e415748a104f0479f54dd642d66011e8 to your computer and use it in GitHub Desktop.
Save meskarune/e415748a104f0479f54dd642d66011e8 to your computer and use it in GitHub Desktop.
conky calendar and weather
#!/usr/bin/env lua
conky_color = "${color1}%2d${color}"
t = os.date('*t', os.time())
year, month, currentday = t.year, t.month, t.day
daystart = os.date("*t",os.time{year=year,month=month,day=01}).wday
month_name = os.date("%B")
days_in_month = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
}
-- check for leap year
-- Any year that is evenly divisible by 4 is a leap year
-- Any year that is evenly divisible by 100 is a leap year if
-- it is also evenly divisible by 400.
LeapYear = function (year)
return year % 4 == 0 and (year % 100 ~= 0 or year % 400 == 0)
end
if LeapYear(year) then
days_in_month[2] = 29
end
title_start = (20 - (string.len(month_name) + 5)) / 2
title = string.rep(" ", math.floor(title_start+0.5)) .. -- add padding to center the title
(" %s %s\n Su Mo Tu We Th Fr Sa\n"):format(month_name, year)
io.write(title)
function seq(a,b)
if a > b then
return
else
return a, seq(a+1,b)
end
end
days = days_in_month[month]
io.write(
string.format(
string.rep(" ", daystart-1) ..
string.rep(" %2d", days), seq(1,days)
):gsub(string.rep(".",21),"%0\n")
:gsub(("%2d"):format(currentday),
(conky_color):format(currentday),
1
) .. "\n"
)
-- vim: ts=4 sw=4 noet ai cindent syntax=lua
conky.config = {
alignment = 'top_right',
background = false,
border_width = 0,
cpu_avg_samples = 2,
default_color = 'cccccc',
color1 = '86b5ea',
default_outline_color = 'cccccc',
default_shade_color = '7a999c',
double_buffer = true,
draw_borders = false,
draw_graph_borders = false,
draw_outline = false,
draw_shades = false,
use_xft = true,
font = 'Fira Sans:normal:size=14',
gap_x = 10,
gap_y = 41,
minimum_height = 5,
minimum_width = 231,
maximum_width = 231,
net_avg_samples = 2,
no_buffers = true,
out_to_console = false,
out_to_stderr = false,
extra_newline = false,
own_window = true,
own_window_class = 'Conky',
own_window_transparent = true,
own_window_type = 'desktop',
stippled_borders = 0,
update_interval = 1.0,
uppercase = false,
use_spacer = 'none',
show_graph_scale = false,
show_graph_range = false,
}
conky.text = [[
${alignc}${font :size=28} ${time %k:%M %p}${font}
${font Fira Mono:size=14}${execpi 3600 ~/.config/conky/cal.lua}${font}
${alignc}${execpi 1800 ~/.config/conky/weather.lua}
]]
#!/usr/bin/lua
https = require("ssl.https")
json = require("json")
-- To use edit variables below for your timezone and location then add the next line to your conky config, uncommented
-- ${alignc}${execpi 3600 ~/.config/conky/moonphase.lua}
-- Change to your timezone offset
tz = "-0"
-- Change to the lattitude and longitude you want to use
lat = "51.5"
long = "-0.116667"
curdate = os.date("!%Y%m%d")
curtime = os.date("!%Y%m%d%H%M%S")
api_url = ("https://api.solunar.org/solunar/%s,%s,%s,%s"):format(lat,long,curdate,tz)
moon = {
["New Moon"] = "🌑",
["Waxing Crescent"] = "🌒",
["First Quarter"] = "🌓",
["Waxing Gibbous"] = "🌔",
["Full moon"] = "🌕",
["Waning Gibbous"] = "🌖",
["Third Quarter"] = "🌗",
["Waning Crescent"] = "🌘"
}
file_exists = function (name)
f=io.open(name,"r")
if f~=nil then
f:close()
return true
else
return false
end
end
if file_exists("moonphase.json") then
cache = io.open("moonphase.json","r")
data = json.decode(cache:read())
cache:close()
timepassed = os.difftime(curtime, data.timestamp)
else
timepassed = 6000
end
makecache = function (s)
cache = io.open("moonphase.json", "w+")
s.timestamp = curtime
save = json.encode(s)
cache:write(save)
cache:close()
end
if timepassed < 3600 then
response = data
else
mooninfo = https.request(api_url)
if mooninfo then
response = json.decode(mooninfo)
makecache(response)
else
response = data
end
end
phase = response.moonPhase
conky_text = [[${font Symbola:size=20}%s${font} %s]]
io.write((conky_text):format(moon[phase], phase))
#!/usr/bin/env lua
-- load the http socket module
http = require("socket.http")
-- load the json module
json = require("json")
api_url = "https://api.openweathermap.org/data/2.5/onecall?"
-- Your lattitude and longitude
LAT = 51.509865
LON = -0.118092
-- metric or imperial
cf = "metric"
-- get an open weather map api key: http://openweathermap.org/appid
apikey = "api-key"
-- measure is °C if metric and °F if imperial
measure = '°' .. (cf == 'metric' and 'C' or 'F')
wind_units = (cf == 'metric' and 'km/h' or 'mph')
-- Unicode weather symbols to use
icons = {
["01"] = "☀",
["02"] = "🌤",
["03"] = "🌥",
["04"] = "☁",
["09"] = "🌧",
["10"] = "🌦",
["11"] = "🌩",
["13"] = "🌨",
["50"] = "🌫",
}
currenttime = os.date("!%Y%m%d%H%M%S")
file_exists = function (name)
f=io.open(name,"r")
if f~=nil then
f:close()
return true
else
return false
end
end
if file_exists("weather.json") then
cache = io.open("weather.json","r")
data = json.decode(cache:read())
cache:close()
timepassed = os.difftime(currenttime, data.timestamp)
else
timepassed = 6000
end
makecache = function (s)
cache = io.open("weather.json", "w+")
s.timestamp = currenttime
save = json.encode(s)
cache:write(save)
cache:close()
end
if timepassed < 3600 then
response = data
else
weather = http.request(("%slat=%s&lon=%s&exclude=minutely,hourly&units=%s&APPID=%s"):format(api_url, LAT, LON, cf, apikey))
if weather then
response = json.decode(weather)
makecache(response)
else
response = data
end
end
math.round = function (n)
return math.floor(n + 0.5)
end
degrees_to_direction = function (d)
val = math.round(d/22.5)
directions = { [0] = "N", [1] = "NNE", [2] = "NE", [3] = "ENE",
[4] = "E", [5] = "ESE", [6] = "SE", [7] = "SSE",
[8] = "S", [9] = "SSW", [10] = "SW", [11] = "WSW",
[12] = "W", [13] = "WNW", [14] = "NW", [15] = "NNW"
}
return directions[val % 16]
end
temp = response.current.temp
min = response.daily[1].temp.min
max = response.daily[1].temp.max
conditions = response.current.weather[1].description
icon2 = response.current.weather[1].id
icon = response.current.weather[1].icon:sub(1, 2)
humidity = response.current.humidity
wind = response.current.wind_speed
deg = degrees_to_direction(response.current.wind_deg)
sunrise = os.date("%H:%M", response.current.sunrise)
sunset = os.date("%H:%M", response.current.sunset)
forcast_icon = response.daily[2].weather[1].icon:sub(1, 2)
forcast_temp = response.daily[2].temp.day
forcast_conditions = response.daily[2].weather[1].main
conky_text = [[
${font Symbola:size=48}%s ${voffset -10}${font :size=20}${color1}%s${font}${voffset -5}%s${color}
${alignc}${voffset 28} %s
${alignc}High: ${color1}%s%s ${color}Low: ${color1}%s%s${color}
${alignc}Humidity: ${color1}%s%%${color}
${alignc}Wind: ${color1}%s%s %s${color}
${alignc}Tomorrow:
${alignc}${color1}${font Symbola:size=20}%s${font} %s%s %s${color}
${alignc}${font Symbola:size=20}─☀─${font}
${alignc}${color1}%s${color} | ${color1}%s${color}
]]
io.write((conky_text):format(icons[icon],
math.round(temp),
measure,
conditions,
math.round(max),
measure,
math.round(min),
measure,
humidity,
math.round(wind),
wind_units,
deg,
icons[forcast_icon],
math.round(forcast_temp),
measure,
forcast_conditions,
sunrise,
sunset)
)
@meskarune
Copy link
Author

screenshot: screenshot of conky

@alo0oz
Copy link

alo0oz commented Sep 12, 2018

I'm having this following error message:

/usr/bin/lua5.2: /home/arafat/.config/conky/weather/weather.lua:60: attempt to index global 'cache' (a nil value) stack traceback: /home/arafat/.config/conky/weather/weather.lua:60: in function 'makecache' /home/arafat/.config/conky/weather/weather.lua:70: in main chunk [C]: in ?

Can you help me please?

Copy link

ghost commented Nov 11, 2018

Wind direction in weather.lua:80 is decoded wrong. Right solution
`
degrees_to_direction = function (d)
val = math.floor(d/22.5 + 0.5)
directions = {
[0] = "N", [1] = "NNE", [2] = "NE", [3] = "ENE",
[4] = "E", [5] = "ESE", [6] = "SE", [7] = "SSE",
[8] = "S", [9] = "SSW", [10] = "SW", [11] = "WSW",
[12] = "W", [13] = "WNW", [14] = "NW", [15] = "NNW"
}
return directions[val % 16]
end

`

@rew62
Copy link

rew62 commented Jan 12, 2019

@alo0oz - the problem is the path. You can either CD to the path where the script is located or you can edit weather.lua and add:

wdir = os.getenv("HOME").."/path/to/directory/"

Near the top of the script where /path/to/directory/ is your directory.
Then concatenate that variable in the 3 places in the script:
so...

if file_exists(wdir.."weather.json") then
cache = io.open(wdir.."weather.json","r")

and..
cache = io.open(wdir.."weather.json", "w+")

@FSchliephacke
Copy link

FSchliephacke commented Nov 19, 2019

I used your code as a starting point for my own script. I just refactored some of it to lose the global variables. If anyone needs it, here it is.

#!/usr/bin/env lua

local json = require("json")

local function file_exists(name)
	local f = io.open(name, "r")
	if f ~= nil then
		f:close()
		return true
	else
		return false
	end
end

local function write_cache(s)
	local cache = io.open("weather.json", "w+")
	s.timestamp = os.date("!%Y%m%d%H%M%S")
	local save = json.encode(s)
	cache:write(save)
	cache:close()
end

local function read_cache()
        local data
	if file_exists("weather.json") then
		local cache = io.open("weather.json","r")
		data = json.decode(cache:read())
		cache:close()
	end
	return data
end

local function fetch_weather(cf)
	local http = require("socket.http")
	local api_url = "http://api.openweathermap.org/data/2.5/weather?"
	local cityid = "<city_id>"
	local apikey = "<api_key>"
	return http.request(("%sid=%s&units=%s&APPID=%s"):format(api_url, cityid, cf, apikey))
end

local function time_passed(data)
	if data == nil then
		return 6000
	else
		return os.difftime(os.date("!%Y%m%d%H%M%S"), data.timestamp)
	end
end

local function get_response(cf)
	local data = read_cache()
	local timepassed = time_passed(data)
	if timepassed < 3600 then
		return data
	else
		local weather = fetch_weather(cf)
		if weather ~= nil then
			local response = json.decode(weather)
			write_cache(response)
			return response
		else
			return data
		end
	end
end

function conky_main()
	-- metric or imperial
	local cf = "metric"
	local measure = '°' .. (cf == 'metric' and 'C' or 'F')
	local wind_units = (cf == 'metric' and 'kph' or 'mph')
	
	local response = get_response(cf)
        return "..."
end

@meskarune
Copy link
Author

I've updated the script to latest working version. The api stopped giving wind direction so that is removed and min/max temp were added in. I need to clean it up a bit more. Maybe in the future I can also add in 3 day forecast.

@FSchliephacke thanks so much for sharing your script! :D

@meskarune
Copy link
Author

New Screenshot
conkycalweather2019

I am using this icon for the sunrise/sunset but otherwise its the same: ─☀️─

@dmaglio
Copy link

dmaglio commented Jan 4, 2020

fixed some issue in weather.lua

#!/usr/bin/env lua
-- load the http socket module
http = require("socket.http")
-- load the json module
json = require("json")

api_url = "http://api.openweathermap.org/data/2.5/weather?"

-- http://openweathermap.org/help/city_list.txt , http://openweathermap.org/find
cityid = "6542124"

-- metric or imperial
cf = "metric"

-- get an open weather map api key: http://openweathermap.org/appid
apikey = "api key"

-- measure is °C if metric and °F if imperial
measure = "°" .. (cf == "metric" and "C" or "F")
wind_units = (cf == "metric" and "kph" or "mph")

-- Unicode weather symbols to use
icons = {
    ["01"] = "☀️",
    ["02"] = "🌤",
    ["03"] = "🌥",
    ["04"] = "☁",
    ["09"] = "🌧",
    ["10"] = "🌦",
    ["11"] = "🌩",
    ["13"] = "🌨",
    ["50"] = "🌫"
}

currenttime = os.date("!%Y%m%d%H%M%S")

file_exists = function(name)
    f = io.open(name, "r")
    if f ~= nil then
        f:close()
        return true
    else
        return false
    end
end

if file_exists("weather.json") then
    cache = io.open("weather.json", "r")
    data = json.decode(cache:read())
    cache:close()
    timepassed = os.difftime(currenttime, data.timestamp)
else
    timepassed = 6000
end

makecache = function(s)
    cache = io.open("weather.json", "w+")
    s.timestamp = currenttime
    save = json.encode(s)
    cache:write(save)
    cache:close()
end

if timepassed < 3600 then
    response = data
else
    weather = http.request(("%sid=%s&units=%s&APPID=%s"):format(api_url, cityid, cf, apikey))
    if weather then
        response = json.decode(weather)
        makecache(response)
    else
        response = data
    end
end

math.round = function(n)
    return math.floor(n + 0.5)
end

degrees_to_direction = function(d)
    val = math.floor(d / 22.5 + 0.5)
    directions = {
        [00] = "N",
        [01] = "NNE",
        [02] = "NE",
        [03] = "ENE",
        [04] = "E",
        [05] = "ESE",
        [06] = "SE",
        [07] = "SSE",
        [08] = "S",
        [09] = "SSW",
        [10] = "SW",
        [11] = "WSW",
        [12] = "W",
        [13] = "WNW",
        [14] = "NW",
        [15] = "NNW"
    }
    return directions[val % 16]
end

temp = response.main.temp
min = response.main.temp_min
max = response.main.temp_max
conditions = response.weather[1].description
icon2 = response.weather[1].id
icon = response.weather[1].icon:sub(1, 2)
humidity = response.main.humidity
wind = response.wind.speed
deg = degrees_to_direction(response.wind.deg)
sunrise = os.date("%H:%M %p", response.sys.sunrise)
sunset = os.date("%H:%M %p", response.sys.sunset)

conky_text =
    [[
${font Symbola:size=36}%s ${voffset -10}${font :size=10}${color1}%s${font}${voffset 0}%s${color}
${alignc}${voffset 28} %s

${alignc}High: ${color1}%s%s    ${color}Low: ${color1}%s%s${color}

${alignc}Humidity: ${color1}%s%%${color}

${alignc}${font Symbola:size=20}─⯊─${font}
${alignc}${color1}%s${color} | ${color1}%s${color}
]]
io.write(
    (conky_text):format(
        icons[icon],
        math.round(temp),
        measure,
        conditions,
        math.round(max),
        measure,
        math.round(min),
        measure,
        humidity,
        math.round(wind),
        deg,
        sunrise,
        sunset
    )
)

@dmaglio
Copy link

dmaglio commented Jan 4, 2020

Schermata del 2020-01-04 02-17-38
calendar is staggered....

@jnyilas
Copy link

jnyilas commented May 16, 2020

I modified you code slightly to use a JSON cache file in a consistent location:
$HOME/.config/conky

This makes my home directory maintenance much easier. I also cleaned up the output to suite my personal conky configuration.

Here is the updated moonphase.lua:

#!/usr/bin/lua
https = require("ssl.https")
json = require("json")

-- To use edit variables below for your timezone and location then add the next line to your conky config, uncommented
-- ${alignc}${execpi 3600 ~/.config/conky/moonphase.lua}

-- Change to your timezone offset
--- EST -5, EDT -4
tz = "-4"

-- Change to the lattitude and longitude you want to use
lat = "XX.43"
long = "-XX.48"

curdate = os.date("!%Y%m%d")
curtime = os.date("!%Y%m%d%H%M%S")

api_url = ("https://api.solunar.org/solunar/%s,%s,%s,%s"):format(lat,long,curdate,tz)

moon = {
  ["New Moon"] = "🌑",
  ["Waxing Crescent"] = "🌒",
  ["First Quarter"] = "🌓",
  ["Waxing Gibbous"] = "🌔",
  ["Full moon"] = "🌕",
  ["Waning Gibbous"] = "🌖",
  ["Third Quarter"] = "🌗",
  ["Waning Crescent"] = "🌘"
}
cachefile = os.getenv("HOME")..("/.config/conky/moonphase.json")

file_exists = function (name)
    f=io.open(name,"r")
    if f~=nil then
        f:close()
        return true
    else
        return false
    end
end

if file_exists(cachefile) then
    cache = io.open(cachefile,"r")
    data = json.decode(cache:read())
    cache:close()
    timepassed = os.difftime(curtime, data.timestamp)
else
    timepassed = 6000
end
makecache = function (s)
    cache = io.open(cachefile, "w+")
    s.timestamp = curtime
    save = json.encode(s)
    cache:write(save)
    cache:close()
end

if timepassed < 3600 then
    response = data
else
    mooninfo = https.request(api_url)
    if mooninfo then
        response = json.decode(mooninfo)
        makecache(response)
    else
        response = data
    end
end

phase = response.moonPhase
transit = response.moonTransit
rise = response.moonRise
set  = response.moonSet

conky_text = [[${font Symbola:size=20}${alignc}${color2}%s${font} %s
               ${color}Rise: ${color9}%5s
            ${color}Transit: ${color9}%5s
                ${color}Set: ${color9}%5s]]

io.write((conky_text):format(moon[phase], phase, rise, transit, set))

@jnyilas
Copy link

jnyilas commented May 16, 2020

And, I made a similar update to weather.lua to use a consistent cache file in $HOME/.config/conky and a few other cosmetic changes to suite my personal conky configuration.

#!/usr/bin/env lua
-- load the http socket module
http = require("socket.http")
-- load the json module
json = require("json")

api_url = "http://api.openweathermap.org/data/2.5/weather?"

-- http://openweathermap.org/help/city_list.txt , http://openweathermap.org/find
---cityid = "6542124"

-- metric or imperial
cf = "imperial"

-- get an open weather map api key: http://openweathermap.org/appid
apikey = "XXX"

-- measure is °C if metric and °F if imperial
measure = "°" .. (cf == "metric" and "C" or "F")
wind_units = (cf == "metric" and "kph" or "mph")

-- Unicode weather symbols to use
icons = {
    ["01"] = "☀️",
    ["02"] = "🌤",
    ["03"] = "🌥",
    ["04"] = "☁",
    ["09"] = "🌧",
    ["10"] = "🌦",
    ["11"] = "🌩",
    ["13"] = "🌨",
    ["50"] = "🌫"
}

currenttime = os.date("!%Y%m%d%H%M%S")
cachefile = os.getenv("HOME")..("/.config/conky/weather.json")
---print (cachefile)

file_exists = function(name)
    f = io.open(name, "r")
    if f ~= nil then
        f:close()
        return true
    else
        return false
    end
end

if file_exists(cachefile) then
    cache = io.open(cachefile, "r")
    data = json.decode(cache:read())
    cache:close()
    timepassed = os.difftime(currenttime, data.timestamp)
else
    timepassed = 6000
end

makecache = function(s)
    cache = io.open(cachefile, "w+")
    s.timestamp = currenttime
    save = json.encode(s)
    cache:write(save)
    cache:close()
end

if timepassed < 3600 then
    response = data
else
    weather = http.request(("%sid=%s&units=%s&APPID=%s"):format(api_url, cityid, cf, apikey))
    if weather then
        response = json.decode(weather)
        makecache(response)
    else
        response = data
    end
end

math.round = function(n)
    return math.floor(n + 0.5)
end

degrees_to_direction = function(d)
    val = math.floor(d / 22.5 + 0.5)
    directions = {
        [00] = "N",
        [01] = "NNE",
        [02] = "NE",
        [03] = "ENE",
        [04] = "E",
        [05] = "ESE",
        [06] = "SE",
        [07] = "SSE",
        [08] = "S",
        [09] = "SSW",
        [10] = "SW",
        [11] = "WSW",
        [12] = "W",
        [13] = "WNW",
        [14] = "NW",
        [15] = "NNW"
    }
    return directions[val % 16]
end

temp = response.main.temp
min = response.main.temp_min
max = response.main.temp_max
conditions = response.weather[1].description
icon2 = response.weather[1].id
icon = response.weather[1].icon:sub(1, 2)
humidity = response.main.humidity
wind = response.wind.speed
deg = degrees_to_direction(response.wind.deg)
sunrise = os.date("%H:%M %p", response.sys.sunrise)
sunset = os.date("%H:%M %p", response.sys.sunset)

conky_text =
    [[
${font Symbola:size=36}${alignc}${color2}%s ${voffset -10}${font :size=10}${color9}%s${font}${voffset 0}%s
${alignc}${color2}${voffset 28}%s

${alignc}${color}High: ${color9}%s%s    ${color}Low: ${color9}%s%s${color}

${alignc}Humidity: ${color9}%s%%${color}
${alignc}Wind: ${color9}%smph${color} @ ${color9}%s${color}

${alignc}${font Symbola:size=20}─⯊─${font}
${alignc}${color9}%s${color} | ${color9}%s${color}
]]
io.write(
    (conky_text):format(
        icons[icon],
        math.round(temp),
        measure,
        conditions,
        math.round(max),
        measure,
        math.round(min),
        measure,
        humidity,
        math.round(wind),
        deg,
        sunrise,
        sunset
    )
)

@phdzor
Copy link

phdzor commented Jul 18, 2020

How can i move calendar to middle ?

img

@jnyilas
Copy link

jnyilas commented Jul 28, 2020

How can i move calendar to middle ?

img

You can just add the ${alignc} conky directive in your conky.conf:
${font Fira Mono:size=14}${alignc}${execpi 3600 ~/.config/conky/cal.lua}${font}

@meskarune
Copy link
Author

I did a big update for this script. There is a new api and it uses latitude and longitude instead of city ID. It now gives forcaste information along with the current weather.

conkyweathersept2020

@meskarune
Copy link
Author

Wind direction in weather.lua:80 is decoded wrong. Right solution
`
degrees_to_direction = function (d)
val = math.floor(d/22.5 + 0.5)
directions = {
[0] = "N", [1] = "NNE", [2] = "NE", [3] = "ENE",
[4] = "E", [5] = "ESE", [6] = "SE", [7] = "SSE",
[8] = "S", [9] = "SSW", [10] = "SW", [11] = "WSW",
[12] = "W", [13] = "WNW", [14] = "NW", [15] = "NNW"
}
return directions[val % 16]
end

`

Thanks, I added to the script. I can try to update to use local vars as well. Sorry I am a bit slow. Maybe I should move all this to it's own repository at some point.

@stiw47
Copy link

stiw47 commented Dec 22, 2020

How can i move calendar to middle ?
img

You can just add the ${alignc} conky directive in your conky.conf:
${font Fira Mono:size=14}${alignc}${execpi 3600 ~/.config/conky/cal.lua}${font}

Bumping ~5 months old post, cause these days I spent lot of useless, but very very interesting hours - top fun time, to fit these scripts to my taste and positioning of calendar was one of challenges (don't take me wrong: I like to have candy desktop and this kind of modding is very interesting for me - I enjoy it, but I have to say it is useless cause it is :) 👯 👯 :) ).

1st thing: Thanks to @meskarune for scripts and concept!!!

2nd thing: @jnyilas: unfortunately, this couldn't be accomplished with Conky alignment, cause putting any ${offset xx}, ${alignc}, ${alignr}, etc. in front or middle of ${font Fira Mono:size=14}${execpi 3600 ~/.config/conky/cal.lua}${font} will move/align only first line, i.e. December 2020, like this:

image

I am not developer. Usually I am able to edit finished code and fit it to my needs, but this was my first time with Lua and hadn't success to figure out could this be aligned inside cal.lua file. So i used workaround/cheat/hack whatever and piped conky exec line for cal.lua to sed, adding spaces in front to every line:

${font Ubuntu Mono:size=14:style=bold}${execpi 3600 ~/.config/conky/cal.lua | sed 's/^/ /'}${font}

(there are lot of SPACEs between two slashes above / / , but it seems that github code tag is displaying all of them as one SPACE)

Anyway, this is my final desktop and I am happy:

image

I would paste my edit of weather.lua here, cause I made 7 days forecast and will be glad to give my contribution here - @meskarune: please be free to implement it in your script if you want. @ALL: Please note that you will need either to revert back icons to unicode icons in weather.lua or you will need icon font I made for this, where I used someone else icons (or you will need to make that font). Reason why I'm not providing everything right now is because I'm lazy :) . I used lot of someone else work for this and if I want to publish my work, I need to credit all these people properly. It will require some more work and hours and I cannot know will this be interesting for even one person at all. I can promise, if someone wish all resources, I will immediately publish this somewhere with all proper credits and share link here - please just let me know (I subscribed to this topic :) ).

At the end, once again, I am not developer and I believe that this probably can be done better and more elegant, but it doing the job for me and I am ok with that.

weather.lua:

#!/usr/bin/env lua
-- load the http socket module
http = require("socket.http")
-- load the json module
json = require("json")


api_url = "https://api.openweathermap.org/data/2.5/onecall?"

-- Your lattitude and longitude
LAT = <put your latitude here>
LON = <put your longitude here>


-- metric or imperial
cf = "metric"

-- get an open weather map api key: http://openweathermap.org/appid
apikey = "<put your API key here>"

-- measure is °C if metric and °F if imperial
measure = '°' .. (cf == 'metric' and 'C' or 'F')
wind_units = (cf == 'metric' and 'm/s' or 'mph')

-- Font icon to use
icons = {
  ["01d"] = "a",
  ["02d"] = "c",
  ["03d"] = "e",
  ["04d"] = "g",
  ["09d"] = "i",
  ["10d"] = "k",
  ["11d"] = "m",
  ["13d"] = "o",
  ["50d"] = "q",
  ["01n"] = "b",
  ["02n"] = "d",
  ["03n"] = "f",
  ["04n"] = "h",
  ["09n"] = "j",
  ["10n"] = "l",
  ["11n"] = "n",
  ["13n"] = "p",
  ["50n"] = "r",
}

currenttime = os.date("!%Y%m%d%H%M%S")

file_exists = function (name)
    f=io.open(name,"r")
    if f~=nil then
        f:close()
        return true
    else
        return false
    end
end

if file_exists("weather.json") then
    cache = io.open("weather.json","r")
    data = json.decode(cache:read())
    cache:close()
    timepassed = os.difftime(currenttime, data.timestamp)
else
    timepassed = 6000
end

makecache = function (s)
    cache = io.open("weather.json", "w+")
    s.timestamp = currenttime
    save = json.encode(s)
    cache:write(save)
    cache:close()
end

if timepassed < 3600 then
    response = data
else
    weather = http.request(("%slat=%s&lon=%s&exclude=minutely,hourly&units=%s&APPID=%s"):format(api_url, LAT, LON, cf, apikey))
    if weather then
        response = json.decode(weather)
        makecache(response)
    else
        response = data
    end
end

math.round = function (n)
    return math.floor(n + 0.5)
end

degrees_to_direction = function (d)
    val = math.round(d/22.5)
    directions = { [0] = "N", [1] = "NNE", [2] = "NE", [3] = "ENE",
                   [4] = "E", [5] = "ESE", [6] = "SE", [7] = "SSE",
                   [8] = "S", [9] = "SSW", [10] = "SW", [11] = "WSW",
                   [12] = "W", [13] = "WNW", [14] = "NW", [15] = "NNW"
                 }
    return directions[val % 16]
end

daysoftheweek = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}
day = daysoftheweek[os.date("*t").wday]
day1 = daysoftheweek[os.date("*t", (os.time() + 86400)).wday]
day2 = daysoftheweek[os.date("*t", (os.time() + 172800)).wday]
day3 = daysoftheweek[os.date("*t", (os.time() + 259200)).wday]
day4 = daysoftheweek[os.date("*t", (os.time() + 345600)).wday]
day5 = daysoftheweek[os.date("*t", (os.time() + 432000)).wday]
day6 = daysoftheweek[os.date("*t", (os.time() + 518400)).wday]
day7 = daysoftheweek[os.date("*t", (os.time() + 604800)).wday]
temp = response.current.temp
min = response.daily[1].temp.min
max = response.daily[1].temp.max
conditions = response.current.weather[1].description
icon2 = response.current.weather[1].id
icon = response.current.weather[1].icon
humidity = response.current.humidity
wind = response.current.wind_speed
deg = degrees_to_direction(response.current.wind_deg)
sunrise = os.date("%H:%M", response.current.sunrise)
sunset = os.date("%H:%M", response.current.sunset)
forecast1_icon = response.daily[2].weather[1].icon
forecast2_icon = response.daily[3].weather[1].icon
forecast3_icon = response.daily[4].weather[1].icon
forecast4_icon = response.daily[5].weather[1].icon
forecast5_icon = response.daily[6].weather[1].icon
forecast6_icon = response.daily[7].weather[1].icon
forecast7_icon = response.daily[8].weather[1].icon
forecast1_temp = response.daily[2].temp.day
forecast2_temp = response.daily[3].temp.day
forecast3_temp = response.daily[4].temp.day
forecast4_temp = response.daily[5].temp.day
forecast5_temp = response.daily[6].temp.day
forecast6_temp = response.daily[7].temp.day
forecast7_temp = response.daily[8].temp.day
forecast1_conditions = response.daily[2].weather[1].main
forecast2_conditions = response.daily[3].weather[1].main
forecast3_conditions = response.daily[4].weather[1].main
forecast4_conditions = response.daily[5].weather[1].main
forecast5_conditions = response.daily[6].weather[1].main
forecast6_conditions = response.daily[7].weather[1].main
forecast7_conditions = response.daily[8].weather[1].main
forecast1_min = response.daily[2].temp.min
forecast2_min = response.daily[3].temp.min
forecast3_min = response.daily[4].temp.min
forecast4_min = response.daily[5].temp.min
forecast5_min = response.daily[6].temp.min
forecast6_min = response.daily[7].temp.min
forecast7_min = response.daily[8].temp.min
forecast1_max = response.daily[2].temp.max
forecast2_max = response.daily[3].temp.max
forecast3_max = response.daily[4].temp.max
forecast4_max = response.daily[5].temp.max
forecast5_max = response.daily[6].temp.max
forecast6_max = response.daily[7].temp.max
forecast7_max = response.daily[8].temp.max

conky_text = [[
${alignc}${offset -50}${color9}${font Weather_icons_tatosxl_stiw47:size=47}%s${color} ${voffset -5}${font Alpaca Scarlett Demo:size=27}${color1}%s${font}${voffset -13}${font Alpaca Scarlett Demo:size=15}%s${font}${color}
${alignc}${offset 115}${voffset 8}${color1} %s${color}
${alignc}${offset 172}${voffset 3}${font Alpaca Scarlett Demo:size=12}${color5}High:${color} ${color1}%s${color}${font}${font Alpaca Scarlett Demo:size=7}${color1}${voffset -15}%s${voffset}${color}${font}  ${font Alpaca Scarlett Demo:size=12}${color7}${voffset -6}Low:${color} ${color1}${offset 0}%s${color}${font}${font Alpaca Scarlett Demo:size=7}${color1}${voffset -15}%s${voffset}${color}${font}
${alignc}${offset 130}${voffset -10}${font Alpaca Scarlett Demo:size=12}${color3}Humidity:${color} ${color1}%s%%${color}
${alignc}${offset 115}${voffset 5}${color4}Wind:${color} ${color1}%s%s %s${color}${font}
${alignc}${offset 115}${voffset -10}${color FF945E}${font Weather_icons_tatosxl_stiw47:size=70}s${font}${color}
${alignc}${offset 143}${voffset -27}${font Alpaca Scarlett Demo:size=12}${color1}%s${color}${color2} |${color} ${color1}%s${color}${font}
${alignc}${offset -202}${voffset 35}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset -129}${voffset -20}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset -55}${voffset -20}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset 18}${voffset -20}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset 90}${voffset -20}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset 164}${voffset -20}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset 237}${voffset -20}${font Alpaca Scarlett Demo:size=12}${color3}%s
${alignc}${offset -155}${voffset 4}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset -85}${voffset -34}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset -11}${voffset -34}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset 64}${voffset -34}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset 135}${voffset -34}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset 206}${voffset -35}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset 282}${voffset -34}${font Weather_icons_tatosxl_stiw47:size=30}${color9}%s${color}${font}${offset 4}${voffset -7}${color1}${font Alpaca Scarlett Demo:size=11}%s${font}${color}${color1}${font Alpaca Scarlett Demo:size=8}${voffset -14}%s${font}${color}
${alignc}${offset -185}${voffset -10}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset -120}${voffset -14}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset -47}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset 26}${voffset -14}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset 101}${voffset -14}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset 172}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset 246}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color7}%s${color}${color1}%s${color}  ${color5}%s${color}${color1}%s${color}
${alignc}${offset -202}${voffset 10}${font Alpaca Scarlett Demo:size=8}${color1}%s
${alignc}${offset -128}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color1}%s
${alignc}${offset -54}${voffset -14}${font Alpaca Scarlett Demo:size=8}${color1}%s
${alignc}${offset 18}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color1}%s
${alignc}${offset 93}${voffset -14}${font Alpaca Scarlett Demo:size=8}${color1}%s
${alignc}${offset 164}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color1}%s
${alignc}${offset 237}${voffset -13}${font Alpaca Scarlett Demo:size=8}${color1}%s
]]
io.write((conky_text):format(icons[icon],
                             math.round(temp),
                             measure,
                             conditions,
                             math.round(max),
                             measure,
                             math.round(min),
                             measure,
                             humidity,
                             wind,
                             wind_units,
                             deg,
                             sunrise,
                             sunset,
                             day1,
                             day2,
                             day3,
                             day4,
                             day5,
                             day6,
                             day7,
                             icons[forecast1_icon],
                             math.round(forecast1_temp),
                             measure,
                             icons[forecast2_icon],
                             math.round(forecast2_temp),
                             measure,
                             icons[forecast3_icon],
                             math.round(forecast3_temp),
                             measure,
                             icons[forecast4_icon],
                             math.round(forecast4_temp),
                             measure,
                             icons[forecast5_icon],
                             math.round(forecast5_temp),
                             measure,
                             icons[forecast6_icon],
                             math.round(forecast6_temp),
                             measure,
                             icons[forecast7_icon],
                             math.round(forecast7_temp),
                             measure,
                             math.round(forecast1_min),
                             measure,
                             math.round(forecast1_max),
                             measure,
                             math.round(forecast2_min),
                             measure,
                             math.round(forecast2_max),
                             measure,
                             math.round(forecast3_min),
                             measure,
                             math.round(forecast3_max),
                             measure,
                             math.round(forecast4_min),
                             measure,
                             math.round(forecast4_max),
                             measure,
                             math.round(forecast5_min),
                             measure,
                             math.round(forecast5_max),
                             measure,
                             math.round(forecast6_min),
                             measure,
                             math.round(forecast6_max),
                             measure,
                             math.round(forecast7_min),
                             measure,
                             math.round(forecast7_max),
                             measure,
                             forecast1_conditions,
                             forecast2_conditions,
                             forecast3_conditions,
                             forecast4_conditions,
                             forecast5_conditions,
                             forecast6_conditions,
                             forecast7_conditions
                             )
        )

@leonardotrp
Copy link

leonardotrp commented Apr 10, 2021

Hello.
I had a hard time at first to show something, but after a boot it worked.

My suggestion is to create a step-by-step for beginning users. It was not so intuitive for me to have to create an account and a API KEY at api.openweathermap.org and replace it in the wheater.lua file, as well as inform my lat/long values. In any case, this solution has enormous potential. Congratulations!

In my case, for Ubuntu 20.04, as I never developed on the moon (I thought it was pretty cool) I had to run the commands:

sudo apt install lua5.3
sudo apt install lua-socket
sudo apt-install lua-json
chmod 755 ~/.config /conky /*.lua

image

@ACR-Jeff
Copy link

Schermata del 2020-01-04 02-17-38 calendar is staggered....

I know this is an old comment but I just figured this may help others out. I had the same issue. What fixed it for me was choosing a different Mono font. I choose ${font Noto Mono:size=14}

@njogumbugua
Copy link

This is the best conky weather script though it's not working on my end because it's unmaintained

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment