The officially official Devuan Forum!

You are not logged in.

#1 2023-12-03 19:19:37

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

[SOLVED] Weather display in conky, a simple one-line-of-code solution

So i've added weather to my conky display using wttr.in: https://github.com/chubin/wttr.in

Super cool service, only had to install curl for it to work. It will display full info in terminal, but i'm using it with conky and don't need all the details it gives in terminal. It can be a bit tricky to get it to work for your area, it tries by default to do it based on your IP, which wouldn't work quite right for my location so it defaulted to some other area. Play around with it by running in terminal:

curl wttr.in/(add your city, county or lat/long)

You can add a location to the command, in my case again my city is too small and remote for it, but it did recognize me when I typed in my county name, which is great because my county is very small and weather is consistent across it. You can also do it by latitude/longitude.

I set mine to update every 20 minutes, but will probably change to every 30 minutes, the less calls the better as it will freak out on you for too many calls.

You will likely need to use your system's fixed width font to get the arrows in the wind output to work, mine is Monospace Regular:

${voffset -7}${font Monospace Regular:pixelsize=12}${alignc}

Here's the code I used to stack some simple results in my conky:

${execi 1800 curl wttr.in/(enter your city or county or latitude-longitude here, no parentheses)?format="Condition:+%C\n""Temperature:+%t\n""Wind+chill:+%f\n""Humidity:+%h\n""Pressure:+%P\n""Wind:+%w\n""Precipitation:+%p\n"}

And this is the result (ignore the Exaile output below it, lol):

9y9a4o.png

You can add or subtract as you see fit, here is a list of the params you can call up:

To specify your own custom output format, use the special %-notation:

    c    Weather condition,
    C    Weather condition textual name,
    x    Weather condition, plain-text symbol,
    h    Humidity,
    t    Temperature (Actual),
    f    Temperature (Feels Like),
    w    Wind,
    l    Location,
    m    Moon phase 🌑🌒🌓🌔🌕🌖🌗🌘,
    M    Moon day,
    p    Precipitation (mm/3 hours),
    P    Pressure (hPa),
    u    UV index (1-12),

    D    Dawn*,
    S    Sunrise*,
    z    Zenith*,
    s    Sunset*,
    d    Dusk*,
    T    Current time*,
    Z    Local timezone.

(*times are shown in the local timezone)

That's it, works great, simple small solution, just how I like 'em!

Last edited by greenjeans (2023-12-06 01:53:50)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#2 2023-12-03 20:37:12

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Redundant post, issue solved, conserving site resources. wink

Last edited by greenjeans (2023-12-06 01:46:51)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#3 2023-12-03 21:59:52

fsmithred
Administrator
Registered: 2016-11-25
Posts: 2,427  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

I use weather-util to get the weather and dump it in a file. Then I let conky pick lines from the file.

wrapper script: (get-weather)

#!/usr/bin/env bash

if [ -n "$1" ] ; then
	station="$1"
else
	station="klax"
fi

weather -v "$station"

~/.conkyrc lines

{color}${execi 1800 /home/fred/bin/get-weather > .current_weather}   ${execi 1800 awk '/Temperature/ { print $0 }' .current_weather }     ${execi 1800 awk '/Humidity/ { print $0 }' .current_weather} 

or

${color}${execi 1800 /home/fred/bin/get-weather.sh > .current_weather} ${color}${execi 1800 cat .current_weather | grep -E "United|Wind|Sky|Temperature|Dew|Humidity|Pressure"}

Hmm... that first one isn't working right for me. Something wrong with my alighment or width. Play with the output if you want. I'm using the second one.

If you want to see the whole .conkyrc, I'll show you, but I think you can find multiple examples somewhere on this forum. I'm sure there have been some discussions.

Offline

#4 2023-12-03 22:17:04

alexkemp
Member
Registered: 2018-05-14
Posts: 292  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

I think that perhaps I should add my set of Conky to my GitHib repository. Anyway, here is the first of a bunch of scripts:

conky.config = {
-- ~/.conky/conkyrc
-- Conky settings #
	background = false,
	update_interval = 1,

	cpu_avg_samples = 4,
	net_avg_samples = 2,

	override_utf8_locale = true,

	double_buffer = true,
	no_buffers = true,

	text_buffer_size = 2048,
--imlib_cache_size 0

	temperature_unit = 'fahrenheit',

-- Window specifications #

	own_window = true,
-- If own_window is yes, you may use type normal, desktop or override
-- 2015-12-10 commented-out settings below are ordinarily fine
--            current SLiM+xfce4 4.8 require desktop + own_window_argb_visual + _value
--            xfce require compositing ON ((menu):Settings→Windows Manager Tweaks)
--            else not transparent or SLiM background shows under 
-- own_window_type normal
	own_window_type = 'desktop',
-- own_window_transparent yes
	own_window_argb_visual = true,
	own_window_argb_value = 0,
	own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
	own_window_hints = 'below',

	border_inner_margin = 0,
	border_outer_margin = 0,

	minimum_width = 200, minimum_height = 250,--# width, height
	maximum_width = 200,

--## top_left, top_right, top_middle, bottom_left, bottom_right, bottom_middle
--## middle_left, middle_middle, middle_right, or none
	alignment = 'top_right',
	gap_x = 20,
	gap_y = 20,

-- Graphics settings #
	draw_shades = false,
	draw_outline = false,
	draw_borders = false,
	draw_graph_borders = false,

-- Text settings #
	use_xft = true,
	font = 'ubuntu:size=8',
	xftalpha = 0.5,

	uppercase = false,

	temperature_unit = 'celsius',

	default_color = '#FFFFFF',

-- Lua Load  #
-- Note: clock + gauges are hard-coded graphics in clock_rings.lua
--       whilst text is within this file (thus possible disjunction)

--       cpu cpu1    : x=50, y=300,  radius=25
--       cpu cpu2    : x=50, y=300,  radius=20
--       memperc     : x=75, y=350,  radius=25
--       swapperc    : x=100, y=400, radius=25
--       fs_used_perc: x=125, y=450, radius=25
--       downspeedf  : x=150, y=500, radius=25
--       upspeedf    : x=150, y=500, radius=20
	lua_load = '~/.lua/scripts/clock_rings.lua',
	lua_draw_hook_pre = 'clock_rings',

};

conky.text = [[
${voffset 8}${color 9f440d}${font ubuntu:size=16}${time %A}${font}${voffset -8}${alignr}${color FFFFFF}${font ubuntu:size=38}${time %e}${font}
${color FFFFFF}${voffset -30}${color FFFFFF}${font ubuntu:size=18}${time %b}${font}${voffset -3} ${color FFFFFF}${font ubuntu:size=20}${time %Y}${font}${color 9f440d}${hr}
# ${voffset 140}${font ubuntu:size=10}${alignr}HOME${font}
${voffset 150}${font ubuntu:size=10}${alignr}East Midlands Airport:${font}
# local weather in minutes
# EGNX = East Midlands
# EGXW = Waddington
#    see http://www.aviationweather.gov/metar?zoom=8&lat=53.24716&lon=-1.11957&layers=B00FTTFFTFFTT&plottype=model&scale=1&density=all&metric=true&decoded=false&taf=true
# or see http://weather.noaa.gov/weather/GB_cc.html
${font ubuntu:size=12}${color FFFFFF}
# 2016-08-03 http://weather.noaa.gov/pub/data/observations/metar/stations/ withdrawn; now gives 404
# 2018-05-13 http://tgftp.nws.noaa.gov/data/observations/metar/stations/ works
# 2021-09-28 http://tgftp.nws.noaa.gov/data/observations/metar/stations/ fails after update to chimaera
# 2023-10-16 https://www.aviationweather.gov/metar/ fails after site update
${alignr}${execi 300 /home/alexk/.conky/weather.pl EGNX TEMP_C } °C${font}${font ubuntu:size=8}
${alignr}${execi 300 /home/alexk/.conky/weather.pl EGNX TIME }:
# 2021-09-28 original gave mysterious continuous 'ARRAY' result with SKY, now ok ???
${alignr}Sky: ${execi 300 /home/alexk/.conky/weather.pl EGNX SKY }
${alignr}RH: ${execi 300 /home/alexk/.conky/weather.pl EGNX RH }%
${alignr}Vis: ${execi 300 /home/alexk/.conky/weather.pl EGNX VISIBILITY }
${alignr}${execi 300 /home/alexk/.conky/weather.pl EGNX ALT_HP } mBar
${alignr}Wind: ${execi 300 /home/alexk/.conky/weather.pl EGNX WIND_KTS } knots
${alignr}${execi 300 /home/alexk/.conky/weather.pl EGNX WIND_DIR_ENG }
${alignr}${execi 300 /home/alexk/.conky/weather.pl EGNX WIND_DIR_DEG } °
#
# 2021-09-28 below replaced by above due to 'TODO..' response:
# ${alignr}${weather http://tgftp.nws.noaa.gov/data/observations/metar/stations/ EGNX temperature 30} °C${font}${font ubuntu:size=8}
# ${alignr}${weather http://tgftp.nws.noaa.gov/data/observations/metar/stations/ EGNX cloud_cover 30}
# ${alignr}RH: ${weather http://tgftp.nws.noaa.gov/data/observations/metar/stations/ EGNX humidity 30}%
# ${alignr}${weather http://tgftp.nws.noaa.gov/data/observations/metar/stations/ EGNX pressure 30} mBar
# ${alignr}Direction: ${weather http://tgftp.nws.noaa.gov/data/observations/metar/stations/ EGNX wind_dir 30}
# ${alignr}${weather http://tgftp.nws.noaa.gov/data/observations/metar/stations/ EGNX weather 30}${font}
#
# ${image ~/.conky/avlinux.png -p 58,115 -s 85x48}
#
# ${color FFFFFF}${goto 25}${voffset 35}${cpu cpu0}%
${color FFFFFF}${goto 25}${voffset -58}${cpu cpu0}%
${color 9f440d}${goto 25}CPU
${color FFFFFF}${goto 50}${voffset 23}${memperc}%
${color 9f440d}${goto 50}RAM
${color FFFFFF}${goto 75}${voffset 23}${swapperc}%
${color 9f440d}${goto 75}Swap
${color FFFFFF}${goto 100}${voffset 23}${fs_used_perc /}%
${color 9f440d}${goto 100}Disk
${color FFFFFF}${goto 125}${voffset 25}${downspeed eth0}
${color FFFFFF}${goto 125}${upspeed eth0}
${color 9f440d}${goto 125}Net

${color FFFFFF}${font ubuntu:size=8}Uptime: ${uptime_short}
${color FFFFFF}${font ubuntu:size=8}Processes: ${processes}
${color FFFFFF}${font ubuntu:size=8}Running: ${running_processes}

${color 9f440d}${font ubuntu:size=8}${nodename}
# ${pre_exec} has been removed in v1.10.6 conky used in devuan ascii
${execi 65000 lsb_release -ds} $machine
Kernel: ${kernel}
]];

...and here are the clock-rings:

~/.lua/scripts/clock_rings.lua:

--[[
~/.lua/scripts/clock_rings.lua

Clock Rings by Linux Mint (2011) reEdited by despot77

This script draws percentage meters as rings, and also draws clock hands if you want! It is fully customisable; all options are described in the script. This script is based off a combination of my clock.lua script and my rings.lua script.

IMPORTANT: if you are using the 'cpu' function, it will cause a segmentation fault if it tries to draw a ring straight away. The if statement on line 145 uses a delay to make sure that this doesn't happen. It calculates the length of the delay by the number of updates since Conky started. Generally, a value of 5s is long enough, so if you update Conky every 1s, use update_num>5 in that if statement (the default). If you only update Conky every 2s, you should change it to update_num>3; conversely if you update Conky every 0.5s, you should use update_num>10. ALSO, if you change your Conky, is it best to use "killall conky; conky" to update it, otherwise the update_num will not be reset and you will get an error.

To call this script in Conky, use the following (assuming that you save this script to ~/scripts/rings.lua):
    lua_load ~/scripts/clock_rings.lua
    lua_draw_hook_pre clock_rings
    
Changelog:
+ v1.0 -- Original release (30.09.2009)
   v1.1p -- Jpope edit londonali1010 (05.10.2009)
*v 2011mint -- reEdit despot77 (18.02.2011)
]]

settings_table = {
    {
        -- Edit this table to customise your rings.
        -- You can create more rings simply by adding more elements to settings_table.
        -- "name" is the type of stat to display; you can choose from 'cpu', 'memperc', 'fs_used_perc', 'battery_used_perc'.
        name='time',
        -- "arg" is the argument to the stat type, e.g. if in Conky you would write ${cpu cpu0}, 'cpu0' would be the argument. If you would not use an argument in the Conky variable, use ''.
        arg='%I.%M',
        -- "max" is the maximum value of the ring. If the Conky variable outputs a percentage, use 100.
        max=12,
        -- "bg_colour" is the colour of the base ring.
        bg_colour=0xffffff,
        -- "bg_alpha" is the alpha value of the base ring.
        bg_alpha=0.1,
        -- "fg_colour" is the colour of the indicator part of the ring.
        fg_colour=0x0D151D,
        -- "fg_alpha" is the alpha value of the indicator part of the ring.
        fg_alpha=0.2,
        -- "x" and "y" are the x and y coordinates of the centre of the ring, relative to the top left corner of the Conky window.
        x=100, y=150,
        -- "radius" is the radius of the ring.
        radius=50,
        -- "thickness" is the thickness of the ring, centred around the radius.
        thickness=5,
        -- "start_angle" is the starting angle of the ring, in degrees, clockwise from top. Value can be either positive or negative.
        start_angle=0,
        -- "end_angle" is the ending angle of the ring, in degrees, clockwise from top. Value can be either positive or negative, but must be larger than start_angle.
        end_angle=360
    },
    {
        name='time',
        arg='%M.%S',
        max=60,
        bg_colour=0xffffff,
        bg_alpha=0.1,
        fg_colour=0x0D151D,
        fg_alpha=0.4,
        x=100, y=150,
        radius=56,
        thickness=5,
        start_angle=0,
        end_angle=360
    },
    {
        name='time',
        arg='%S',
        max=60,
        bg_colour=0xffffff,
        bg_alpha=0.1,
        fg_colour=0x0D151D,
        fg_alpha=0.6,
        x=100, y=150,
        radius=62,
        thickness=5,
        start_angle=0,
        end_angle=360
    },
    {
        name='time',
        arg='%d',
        max=31,
        bg_colour=0xffffff,
        bg_alpha=0.1,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=100, y=150,
        radius=70,
        thickness=5,
        start_angle=-90,
        end_angle=90
    },
    {
        name='time',
        arg='%m',
        max=12,
        bg_colour=0xffffff,
        bg_alpha=0.1,
        fg_colour=0x0D151D,
        fg_alpha=1,
        x=100, y=150,
        radius=76,
        thickness=5,
        start_angle=-90,
        end_angle=90
    },
    {
        name='cpu',
        arg='cpu1',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=50, y=300,
        radius=25,
        thickness=4,
        start_angle=-90,
        end_angle=180
    },
    {
        name='cpu',
        arg='cpu2',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=50, y=300,
        radius=20,
        thickness=4,
        start_angle=-90,
        end_angle=180
    },
    {
        name='memperc',
        arg='',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=75, y=350,
        radius=25,
        thickness=5,
        start_angle=-90,
        end_angle=180
    },
    {
        name='swapperc',
        arg='',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=100, y=400,
        radius=25,
        thickness=5,
        start_angle=-90,
        end_angle=180
    },
    {
        name='fs_used_perc',
        arg='/',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=125, y=450,
        radius=25,
        thickness=5,
        start_angle=-90,
        end_angle=180
    },
        {
        name='downspeedf',
        arg='eth0',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0x0D151D,
        fg_alpha=0.8,
        x=150, y=500,
        radius=25,
        thickness=4,
        start_angle=-90,
        end_angle=180
    },
        {
        name='upspeedf',
        arg='eth0',
        max=100,
        bg_colour=0xffffff,
        bg_alpha=0.2,
        fg_colour=0xff3300,
        fg_alpha=0.8,
        x=150, y=500,
        radius=20,
        thickness=4,
        start_angle=-90,
        end_angle=180
    },
}

-- Use these settings to define the origin and extent of your clock.

clock_r=65

-- "clock_x" and "clock_y" are the coordinates of the centre of the clock, in pixels, from the top left of the Conky window.

clock_x=100
clock_y=150

show_seconds=true

require 'cairo'

function rgb_to_r_g_b(colour,alpha)
    return ((colour / 0x10000) % 0x100) / 255., ((colour / 0x100) % 0x100) / 255., (colour % 0x100) / 255., alpha
end

function draw_ring(cr,t,pt)
    local w,h=conky_window.width,conky_window.height
    
    local xc,yc,ring_r,ring_w,sa,ea=pt['x'],pt['y'],pt['radius'],pt['thickness'],pt['start_angle'],pt['end_angle']
    local bgc, bga, fgc, fga=pt['bg_colour'], pt['bg_alpha'], pt['fg_colour'], pt['fg_alpha']

    local angle_0=sa*(2*math.pi/360)-math.pi/2
    local angle_f=ea*(2*math.pi/360)-math.pi/2
    local t_arc=t*(angle_f-angle_0)

    -- Draw background ring

    cairo_arc(cr,xc,yc,ring_r,angle_0,angle_f)
    cairo_set_source_rgba(cr,rgb_to_r_g_b(bgc,bga))
    cairo_set_line_width(cr,ring_w)
    cairo_stroke(cr)
    
    -- Draw indicator ring

    cairo_arc(cr,xc,yc,ring_r,angle_0,angle_0+t_arc)
    cairo_set_source_rgba(cr,rgb_to_r_g_b(fgc,fga))
    cairo_stroke(cr)        
end

function draw_clock_hands(cr,xc,yc)
    local secs,mins,hours,secs_arc,mins_arc,hours_arc
    local xh,yh,xm,ym,xs,ys
    
    secs=os.date("%S")    
    mins=os.date("%M")
    hours=os.date("%I")
        
    secs_arc=(2*math.pi/60)*secs
    mins_arc=(2*math.pi/60)*mins+secs_arc/60
    hours_arc=(2*math.pi/12)*hours+mins_arc/12
        
    -- Draw hour hand
    
    xh=xc+0.7*clock_r*math.sin(hours_arc)
    yh=yc-0.7*clock_r*math.cos(hours_arc)
    cairo_move_to(cr,xc,yc)
    cairo_line_to(cr,xh,yh)
    
    cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND)
    cairo_set_line_width(cr,5)
    cairo_set_source_rgba(cr,1.0,1.0,1.0,1.0)
    cairo_stroke(cr)
    
    -- Draw minute hand
    
    xm=xc+clock_r*math.sin(mins_arc)
    ym=yc-clock_r*math.cos(mins_arc)
    cairo_move_to(cr,xc,yc)
    cairo_line_to(cr,xm,ym)
    
    cairo_set_line_width(cr,3)
    cairo_stroke(cr)
    
    -- Draw seconds hand
    
    if show_seconds then
        xs=xc+clock_r*math.sin(secs_arc)
        ys=yc-clock_r*math.cos(secs_arc)
        cairo_move_to(cr,xc,yc)
        cairo_line_to(cr,xs,ys)
    
        cairo_set_line_width(cr,1)
        cairo_stroke(cr)
    end
end

function conky_clock_rings()
    local function setup_rings(cr,pt)
        local str=''
        local value=0
        
        str=string.format('${%s %s}',pt['name'],pt['arg'])
        str=conky_parse(str)
        
        value=tonumber(str)
        pct=value/pt['max']
        
        draw_ring(cr,pct,pt)
    end
    
    -- Check that Conky has been running for at least 5s

    if conky_window==nil then return end
    local cs=cairo_xlib_surface_create(conky_window.display,conky_window.drawable,conky_window.visual, conky_window.width,conky_window.height)
    
    local cr=cairo_create(cs)    
    
    local updates=conky_parse('${updates}')
    update_num=tonumber(updates)
    
    if update_num>5 then
        for i in pairs(settings_table) do
            setup_rings(cr,settings_table[i])
        end
    end
    
    draw_clock_hands(cr,clock_x,clock_y)
end

Last edited by alexkemp (2023-12-03 22:35:14)

Online

#5 2023-12-03 22:32:46

alexkemp
Member
Registered: 2018-05-14
Posts: 292  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

This is a barometer:

~/.conky/conkyrc.weather:

conky.config = {
-- .conky/conkyrc.weather
-- draw barometer

-- Conky settings #
	background = false,
	update_interval = 1,

	cpu_avg_samples = 2,
	net_avg_samples = 2,

	override_utf8_locale = true,

	double_buffer = true,
	no_buffers = true,

	text_buffer_size = 2048,
--imlib_cache_size 0

	temperature_unit = 'fahrenheit',

-- Window specifications #

	own_window = true,
-- If own_window is yes, you may use type normal, desktop or override
-- 2015-12-10 commented-out settings below are ordinarily fine
--            current SLiM+xfce4 4.8 require desktop + own_window_argb_visual + _value
--            xfce require compositing ON ((menu):Settings→Windows Manager Tweaks)
--            else not transparent or SLiM background shows under 
-- own_window_type normal
	own_window_type = 'normal',
-- own_window_transparent yes
	own_window_argb_visual = true,
	own_window_argb_value = 0,
	own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',

	border_inner_margin = 6,
	border_outer_margin = 3,

	minimum_width = 250, minimum_height = 250,--# width, height
	maximum_width = 250,

--## top_left, top_right, top_middle, bottom_left, bottom_right, bottom_middle
--## middle_left, middle_middle, middle_right, or none
	alignment = 'bottom_left',
	gap_x = 0,
	gap_y = 30,

-- Graphics settings #
	draw_shades = false,
	draw_outline = false,
	draw_borders = false,
	draw_graph_borders = false,

-- Text settings #
	use_xft = true,
	font = 'ubuntu:size=8',
	xftalpha = 0.5,

	uppercase = false,

	temperature_unit = 'celsius',

	default_color = '#FFFFFF',

-- Lua Load  #
	lua_load = '~/.lua/scripts/weather.lua',
	lua_draw_hook_pre = 'conky_draw_test',
};

conky.text = [[
# No TEXT in weather config  #

]];

...and here the actual draw-barometer script:

~/.lua/scripts/weather.lua:

--[[ ~/.lua/scripts/weather.lua
      analogue barometer
 2020-11-17 v 1.1 added CSV export for graphs
 2015-06-21 v 1.0 edited by Alex Kemp
 2011-05-27 original from Tim CowChip @ http://forum.salixos.org/viewtopic.php?p=26545

A good Conky/Lua HowTo:-
http://crunchbang.org/forums/viewtopic.php?id=17246
]]

require 'cairo'
require 'imlib2'

static=0       --value for barometer static pointer
old_pressure=0 --value to trip csv updates
update=nil

--[[ barometer()
 Display an analogue barometer

 @param  cr cairo resource
 @param  pr pressure (mBar or inches Mercury)
 @param  px x centre-position, pixels
 @param  py y centre-position, pixels
 @return (none)
]]
function barometer(cr,pr,px,py)
   --setup table; change barometer appearance
   --htm2col(col,alpha) available for html colour conversion
   local st={
      ctCOL  ={htm2col(0x68441b,1)},     --circle txt colour
      ctFNT  ="URW Chancery L",          --circle txt font name
      ctSize =20,                        --circle txt font size
      ctSLNT =CAIRO_FONT_SLANT_ITALIC,   --circle txt font slant
      ctChang="Change",                  --circle txt 'CHANGE' text
      ctFair ="Fair",                    --circle txt 'FAIR'   text
      ctRain ="Rain",                    --circle txt 'RAIN'   text
      ctStorm="Stormy",                  --circle txt 'STORM'  text
      ctVDry ="Very Dry",                --circle txt 'V DRY'  text
      ctWT   =CAIRO_FONT_WEIGHT_BOLD,    --circle txt font weight
      lw     =5,                         --outer line-width (added to ro)
      ro     =100,                       --radius to outer rim
      bkCOL  ={htm2col(0xf5f5f5,1)},     --background colour
      roCOL  ={htm2col(0x31200d,1)},     --outer rim  colour
      pbCOL  ={0,0,0,0},                 --ptr back   colour
      pfCOL  ={1,0,0,1},                 --ptr fore   colour
      ppCOL  ={0,0,0,1},                 --ptr pivot  colour
      psCOL  ={htm2col(0x68441b,1)},     --ptr static colour
      --psCOL  ={htm2col(0xcdc674,1)},     --ptr static colour
      text   ="Pressure",                --text       text
      txCOL  ={0,0,0,1},                 --text       colour
   }
--[[ barometer 27 inches to 32 inches = 5 inches
              940 Mbar to 1060 millibar 
 'ro*<some-number:0,1>' appears regularly below
 all calcs are based on original radius=100px
 they allow the barometer to be re-sized (within limits)
 eg 'ro*0.75'==a ring at 75 pixels based on orig 100px radius

 circle-text: 87px
     pointer:  7px inner, 75px outer
Pressure txt: 90px
              text : rad outer  : radius inner
  inch scale: 77px : 75,70,68px : 65px
 mbar scale:  37px : 60px       : 55,50px

 line basics: cairo_set_line_cap(cr,CAIRO_LINE_CAP_BUTT) default
              cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND)
              cairo_set_line_cap(cr,CAIRO_LINE_CAP_SQUARE)

  arc basics: cairo_arc(cr,centre_x,centre_y,radius,start_angle,end_angle)
              angles are in radians 
              centre + radius are in pixels
              radians=degrees*(math.pi/180)
              0 radians = East (RHS)
                        = 2*math.pi (360 degrees)
]]
   --draw outer rim; fill + stroke
   local lw =st.lw       or 1   -- line-width of outer rim
   local ro =st.ro       or 100 -- radius     of outer rim
   local r  =st.bkCOL[1] or 0.1 -- red   component of background colour
   local g  =st.bkCOL[2] or 0.1 -- green component of background colour
   local b  =st.bkCOL[3] or 0.1 -- blue  component of background colour
   local a  =st.bkCOL[4] or 1   -- alpha component of background colour
   local ARC=2*math.pi          -- 360 degrees
   local D2R=math.pi/180        -- degrees to radians conversion ratio
   cairo_set_line_width(cr,lw)
   cairo_set_source_rgba(cr,r,g,b,a)
   cairo_arc(cr,px,py,ro+lw,0,ARC)
   cairo_fill (cr)
   local r =st.roCOL[1] or 1 -- red   component of outer rim  colour
   local g =st.roCOL[2] or 1 -- green component of outer rim  colour
   local b =st.roCOL[3] or 1 -- blue  component of outer rim  colour
   local a =st.roCOL[4] or 1 -- alpha component of outer rim  colour
   cairo_set_source_rgba(cr,r,g,b,a)
   cairo_arc(cr,px,py,ro+lw,0,ARC)
   cairo_stroke(cr)
   --draw inch + mbar scales
   local r =st.txCOL[1] or 1 -- red   component of text colour
   local g =st.txCOL[2] or 1 -- green component of text colour
   local b =st.txCOL[3] or 1 -- blue  component of text colour
   local a =st.txCOL[4] or 1 -- alpha component of text colour
   --draw inch scale; rout==outer radius; rin==inner radius
   local rout1=ro*0.75
   local rin1=rout1-(ro*0.10)
   for i=0,40 do
      if i==5 or i==15 or i==25 or i==35 then
         rout=rout1-(ro*0.07)
         cairo_set_source_rgba(cr,r,g,b,a)
         cairo_set_line_width(cr,3)
      elseif i==0 or i==10 or i==20 or i==30 or i==40 then
         rout=rout1
         cairo_set_line_width(cr,1)
      else
         rout=rout1-(ro*0.05)
         cairo_set_line_width(cr,1)
      end
      arc=D2R*(210+(i*(300/40)))
      ppx=0+rout*(math.sin(arc))
      ppy=0-rout*(math.cos(arc))
      arc=D2R*(210+(i*300/40))
      pix=0+rin1*(math.sin(arc))
      piy=0-rin1*(math.cos(arc))
      cairo_move_to(cr,px+ppx,py+ppy)
      cairo_line_to(cr,px+pix,py+piy)
      cairo_stroke(cr)
   end
   --draw inch text
   inch={28,29,30,31}
   local rout=rout1+2
   for i=1,4 do
      arc=D2R*(210+(300/8)+((i-1)*(300/4)))
      ppx=0+rout*(math.sin(arc))
      ppy=0-rout*(math.cos(arc))
      text=inch[i]
      extents=cairo_text_extents_t:create()
      cairo_text_extents(cr,text,extents)
      width=extents.width
      height=extents.height
      cairo_move_to(cr,px+ppx-(width/2),py+ppy+(height/2))
      cairo_show_text(cr,text)
      cairo_stroke(cr)
   end
   --942 to 1056
   --27.5=931.25
   --31.5=1066.70
   --draw mbar scale; rout==outer radius; rin==inner radius
   cairo_set_line_width(cr,1)
   local m1=300/135.45
   local m2=m1*8.75--931.25+8.75=940
   local rout2=(ro*0.60)
   local rin2=rout2-(ro*0.05)
   local num=60
   for i=0,num do
      if i==0 or i==5 or i==10 or i==15 or i==20 or i==25 or i==30 or i==35 or i==40 or i==45 or i==50 or i==55 or i==60 or i==65 then
         rin=rin2-(ro*0.05)
      else
         rin=rin2
      end
--    arc=D2R*(210+m2+(i*((m1*(num*2))/num)))
      arc=D2R*(210+m2+(i*m1*2))
      ppx=0+rout2*(math.sin(arc))
      ppy=0-rout2*(math.cos(arc))
      pix=0+rin*(math.sin(arc))
      piy=0-rin*(math.cos(arc))
      cairo_move_to (cr,px+ppx,py+ppy)
      cairo_line_to (cr,px+pix,py+piy)
      cairo_stroke (cr)
   end
   --draw mbar text
   inch={940,960,980,1000,1020,1040,1060}
   local rout=rin2-(ro*0.18)
   local maxW=0
   for i=1,7 do
      arc=D2R*(210+m2+((i-1)*(m1*20)))
      ppx=0+rout*(math.sin(arc))
      ppy=0-rout*(math.cos(arc))
      text=inch[i]
      extents=cairo_text_extents_t:create()
      cairo_text_extents(cr,text,extents)
      width=extents.width
      height=extents.height
      if  width>maxW  then maxW=width  end
      cairo_move_to(cr,px+ppx-(width/2),py+ppy+(height/2))
      cairo_show_text(cr,text)
      cairo_stroke(cr)
   end
   --scale labels
   local text="inches hg"
   local extents=cairo_text_extents_t:create()
   cairo_text_extents(cr,text,extents)
   local width=extents.width
   local height=extents.height
   cairo_move_to(cr,px-(width/2),py+rin1)
   cairo_show_text(cr,text)
   cairo_stroke(cr)
   local text="millibars"
   extents=cairo_text_extents_t:create()
   cairo_text_extents(cr,text,extents)
   local width=extents.width
   local height=extents.height
   cairo_move_to(cr,px-(width/2),py+rin2-height)
   cairo_show_text(cr,text)
   cairo_stroke(cr)
   local text=st.text or "Pressure";
   extents=cairo_text_extents_t:create()
   cairo_text_extents(cr,text,extents)
   local width=extents.width
   local height=extents.height
   cairo_move_to(cr,px-(width/2),py+rin2+(ro*0.35))
   cairo_show_text(cr,text)
   cairo_stroke(cr)
--[[ draw pointer
  psx,psy static  tip,  rout1 radius
  ptx,pty pointer tip,  rout1 radius
  pbx,pby pointer base, rout  radius w/adjust for inner text width
  pex,pey pb end cap,   rout  radius

  static pointer has value set at first value of pressure>0

  expects pressure in inches Hg
  1 inch Hg == 33.8638866667 mBar
]]
   pr=tonumber(pr)
   local pres=1
   if pr==nil or pr<1 then pr=27.5 end--account for nil/zero value
   if pr>500  then
      -- it's in mBar; convert to inches
      pres=(pr/33.8638867) - 27.5
   else
      -- it's in inches, or we're all dead
      pres=pr-27.5
   end
   if static<1 and pres>0 then
      --static pointer value
      static=pres
   end
   local m1=300/4            -- top part of ptr
   local m2=pres*m1
   local arc=D2R*(210+m2)
   local sin=math.sin(arc)
   local cos=math.cos(arc)
   local ptx=px+rout1*sin
   local pty=py-rout1*cos
   ------------------------------
   arc=D2R*(210+m2+180)      -- bottom part of ptr
   sin=math.sin(arc)
   cos=math.cos(arc)
   local pbx=px+((rout-maxW)*sin)
   local pby=py-((rout-maxW)*cos)
   local pex=px+((rout-(2*maxW/3))*sin)
   local pey=py-((rout-(2*maxW/3))*cos)
   --------------------------------
   local psx,psy,arb         -- static ptr
   if ((static<1) or (static==pres)) then
      psx,psy=ptx,pty
   else
      m2=static*m1
      arb=D2R*(210+m2)
      sin=math.sin(arb)
      cos=math.cos(arb)
      psx=px+rout1*sin
      psy=py-rout1*cos
   end
   --------------------------------
   local r =st.pfCOL[1] or 0 -- red   component of ptr fore   colour
   local g =st.pfCOL[2] or 0 -- green component of ptr fore   colour
   local b =st.pfCOL[3] or 0 -- blue  component of ptr fore   colour
   local a =st.pfCOL[4] or 1 -- alpha component of ptr fore   colour
   cairo_set_source_rgba(cr,r,g,b,a)
   cairo_set_line_width(cr,3)
   cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND)
   cairo_arc(cr,pex,pey,maxW/3,arc,arc-math.pi)
   cairo_move_to(cr,ptx,pty)
   cairo_line_to(cr,pbx,pby)
   cairo_move_to(cr,px,py)
   cairo_arc(cr,px,py,ro*0.04,0,ARC)
   cairo_stroke(cr)
   --------------------------------
   local r  =st.bkCOL[1] or 0.1 -- red   component of background colour
   local g  =st.bkCOL[2] or 0.1 -- green component of background colour
   local b  =st.bkCOL[3] or 0.1 -- blue  component of background colour
   local a  =st.bkCOL[4] or 1   -- alpha component of background colour
   cairo_set_source_rgba(cr,r,g,b,a)
   cairo_arc(cr,px,py,ro*0.02,0,ARC)
   --cairo_arc(cr,px,py,ro*0.03,0,ARC)
   cairo_fill(cr)
   --------------------------------
   local r  =st.psCOL[1] or 0   -- red   component of static ptr colour
   local g  =st.psCOL[2] or 0   -- green component of static ptr colour
   local b  =st.psCOL[3] or 0   -- blue  component of static ptr colour
   local a  =st.psCOL[4] or 1   -- alpha component of static ptr colour
   cairo_set_source_rgba(cr,r,g,b,a)
   cairo_set_line_width(cr,1)
   cairo_move_to(cr,psx,psy)
   cairo_line_to(cr,px,py)
   cairo_stroke(cr)
   cairo_arc(cr,px,py,ro*0.02,0,ARC)
   --cairo_arc(cr,px,py,ro*0.04,0,ARC)
   cairo_fill(cr)
--[[ original pointer
-- begin speedo-type pointer (alpha=0 - no bottom part of pointer)
--    or magnet-type pointer (alpha=1 for top&bottom)
   local m1=300/4
   local m2=pres*m1
   local rout1=rout1
   local arc=D2R*(210+m2)
   local ppx=0+rout1*(math.sin(arc))
   local ppy=0-rout1*(math.cos(arc))
   ------------------------------
   local arc=D2R*(210+m2+180)
   local ppox=0+rout1*(math.sin(arc))
   local ppoy=0-rout1*(math.cos(arc))
   -------------------------------
   local rin3=(ro*0.07)
   local arc=D2R*(210+m2-90)
   local pilx=0+rin3*(math.sin(arc))
   local pily=0-rin3*(math.cos(arc))
   local arc=D2R*(210+m2+90)
   local pirx=0+rin3*(math.sin(arc))
   local piry=0-rin3*(math.cos(arc))
   --------------------------------
   local r =st.pfCOL[1] or 1 -- red   component of ptr fore   colour
   local g =st.pfCOL[2] or 0 -- green component of ptr fore   colour
   local b =st.pfCOL[3] or 0 -- blue  component of ptr fore   colour
   local a =st.pfCOL[4] or 1 -- alpha component of ptr fore   colour
   cairo_move_to(cr,px+pilx,py+pily)
   cairo_line_to(cr,px+ppx,py+ppy)
   cairo_line_to(cr,px+pirx,py+piry)
   cairo_line_to(cr,px+pilx,py+pily)
   cairo_set_source_rgba(cr,r,g,b,a)
   cairo_fill(cr)
   cairo_arc(cr,px,py,rin3,0,ARC)
   cairo_fill(cr)
   ---------------------------------
   local r =st.pbCOL[1] or 1 -- red   component of ptr back   colour
   local g =st.pbCOL[2] or 1 -- green component of ptr back   colour
   local b =st.pbCOL[3] or 1 -- blue  component of ptr back   colour
   local a =st.pbCOL[4] or 1 -- alpha component of ptr back   colour
   cairo_move_to (cr,px+pilx,py+pily)
   cairo_line_to (cr,px+ppox,py+ppoy)
   cairo_line_to (cr,px+pirx,py+piry)
   cairo_line_to (cr,px+pilx,py+pily)
   cairo_set_source_rgba (cr,r,b,g,a)
   cairo_fill (cr)
   local r =st.pfCOL[1] or 1 -- red   component of ptr fore   colour
   local g =st.pfCOL[2] or 0 -- green component of ptr fore   colour
   local b =st.pfCOL[3] or 0 -- blue  component of ptr fore   colour
   local a =st.pfCOL[4] or 1 -- alpha component of ptr fore   colour
   cairo_set_source_rgba (cr,r,g,b,a)
   cairo_arc (cr,px,py,rin3,0,ARC)
   cairo_fill (cr)
   -----------------------------------
   local r =st.ppCOL[1] or 0 -- red   component of ptr pivot  colour
   local g =st.ppCOL[2] or 0 -- green component of ptr pivot  colour
   local b =st.ppCOL[3] or 0 -- blue  component of ptr pivot  colour
   local a =st.ppCOL[4] or 1 -- alpha component of ptr pivot  colour
   cairo_set_source_rgba (cr,r,g,b,a)
   cairo_arc (cr,px,py,rin3-1,0,ARC)
   cairo_fill (cr)
-- end   car   -type pointer (alpha=0 so no bottom part of pointer) ]]

   ----circle text
   local horiz=px
   local verti=py
   local radi=(ro*0.87)
   local font=st.ctFNT   or "Mono";
   local text=st.ctStorm or "STORMY";
   local size=st.ctSize  or 12;
   local fsize=(ro*size/100)
   local start=250
   local finish=start+((string.len(text))*5)
   circlewriting(cr, text, font, fsize, radi, horiz, verti, start, finish,st)
   local text=st.ctRain  or "RAIN";
   local start=300
   local finish=start+((string.len(text))*5)
   circlewriting(cr, text, font, fsize, radi, horiz, verti, start, finish,st)
   local text=st.ctChang or "CHANGE";
   local start=340
   local finish=start+((string.len(text))*5)
   circlewriting(cr, text, font, fsize, radi, horiz, verti, start, finish,st)
   local text=st.ctFair  or "FAIR";
   local start=395
   local finish=start+((string.len(text))*5)
   circlewriting(cr, text, font, fsize, radi, horiz, verti, start, finish,st)
   local text=st.ctVDry  or "VERY DRY";
   local start=435
   local finish=start+((string.len(text))*5)
   circlewriting(cr, text, font, fsize, radi, horiz, verti, start, finish,st)
end-- function barometer

------------------------------------------------------------------------------
function circlewriting(cr, text, font, fsize, radi, horiz, verti, start, finish, st)
   local r =st.ctCOL[1] or 1 -- red   component of circle txt colour
   local g =st.ctCOL[2] or 1 -- green component of circle txt colour
   local b =st.ctCOL[3] or 1 -- blue  component of circle txt colour
   local a =st.ctCOL[4] or 1 -- alpha component of circle txt colour
   local s =st.ctSLNT   or CAIRO_FONT_SLANT_NORMAL  -- font slant  setting
   local w =st.ctWT     or CAIRO_FONT_WEIGHT_NORMAL -- font weight setting
    cairo_select_font_face (cr, font, s, w);
    cairo_set_font_size (cr, fsize)
    cairo_set_source_rgba (cr,r,g,b,a);
    local inum=string.len(text)
    local deg=(finish-start)/(inum-1)
    local degrads=(math.pi/180)
    local textcut=string.gsub(text, ".", "%1|")
    texttable=string.split(textcut, "|")
    for i=1,inum do
    interval=(degrads*(start+(deg*(i-1))))
    txs=0+radi*(math.sin(interval))
    tys=0-radi*(math.cos(interval))
    cairo_move_to (cr, txs+horiz, tys+verti);
    cairo_rotate (cr, interval)
    cairo_show_text (cr, (texttable[i]))
    cairo_stroke (cr)
    cairo_rotate (cr, -interval)
    end
end--function circlewriting

------------------------------------------------------------------------------
--[[ savecsv()
 Save barometer stats as a CSV file

 @param  dt datetime (YYYY-MM-DD (ISO 8601) + HH:DD UTC)
 @param  lo location of CSV file in filesystem
 @param  pr pressure (mBar or inches Mercury)
 @return (none)

 update always = 1 at entry to this function
 lo may NOT exist at entry if first-time save
]]
function savecsv(dt,lo,pr)
   -- first check if lo exists & create if not
   local f, err = io.open(lo, "r")
	local file
   if f~=nil then
      -- file exists; now open in append-mode
      f:close()
      file, err = io.open(lo, "a+")
      if file==nil then
         print("Error opening file "..lo..":"..err)
      end
   else
      -- file NOT exist; create in append-mode
      local header="'Time','Barometer'\n"
      file, err = io.open(lo, "a+")
      if file then
         file:write(header)
      else
         print("Error creating new file "..lo..":"..err)
      end
   end

   if file then
      file:write("'"..dt.."','"..pr.."'\n")
      file:close()
   end
end-- function savecsv

    ------------------------------------------------------------------------------
    function string:split(delimiter)
    local result = { }
    local from  = 1
    local delim_from, delim_to = string.find( self, delimiter, from  )
    while delim_from do
    table.insert( result, string.sub( self, from , delim_from-1 ) )
    from  = delim_to + 1
    delim_from, delim_to = string.find( self, delimiter, from  )
    end
    table.insert( result, string.sub( self, from  ) )
    return result
    end
    --------------------------------------------------------------------------------
    function wspeed_dial(ws,px,py)
    --0 to 60 mph
    --draw circle
    cairo_set_line_width (cr,1)
    local router=110
    cairo_set_source_rgba (cr,0.1,0.1,0.1,1)
    cairo_arc (cr,px,py,router,0,(2*math.pi))
    cairo_fill (cr)
    cairo_set_source_rgba (cr,1,1,1,1)
    cairo_arc (cr,px,py,router,0,(2*math.pi))
    cairo_stroke (cr)
    -------------------------------------------
    --mph scale
    local rout1=80
    local rin1=rout1-10
    for i=0,60 do
    if i==5 or i==15 or i==25 or i==35 or i==45 then
    rin=rin1--set line length for 5s
    cairo_set_line_width (cr,1)
    elseif i==0 or i==10 or i==20 or i==30 or i==40 or i==50 or i==60 then
    rin=rin1+7--set line length for 10's
    cairo_set_line_width (cr,3)
    else
    rin=rin1+5--set other lines
    cairo_set_line_width (cr,1)
    end--if i==
    arc=(math.pi/180)*(210+(i*(300/60)))
    ppx=0+rout1*(math.sin(arc))
    ppy=0-rout1*(math.cos(arc))
    arc=(math.pi/180)*(210+(i*300/60))
    pix=0+rin*(math.sin(arc))
    piy=0-rin*(math.cos(arc))
    cairo_move_to (cr,px+ppx,py+ppy)
    cairo_line_to (cr,px+pix,py+piy)
    cairo_stroke (cr)
    end--for i=
    --mph reading
    mph={0,10,20,30,40,50,60}
    local rin=rin1-2
    for i=1,#mph do
    arc=(math.pi/180)*(210+((i-1)*(300/6)))
    ppx=0+rin*(math.sin(arc))
    ppy=0-rin*(math.cos(arc))
    text=mph[i]
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    width=extents.width
    height=extents.height
    cairo_move_to (cr,px+ppx-(width/2),py+ppy+(height/2))
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end--for i= print inches
    --kmh lines and numbers
    --60kmh=96.5606
    cairo_set_line_width (cr,1)
    local m1=300/96.5606
    local rout2=60
    local rin2=rout2-5
    local num=95
    --print lines---------------
    for i=0,num do
    if i==0 or i==10 or i==20 or i==30 or i==40 or i==50 or i==60 or i==70 or i==80 or i==90 then
    rin=rin2-5--set length for 10s
    elseif i==5 or i==15 or i==25 or i==35 or i==45 or i==55 or i==65 or 1==75 or i==85 or i==95 then
    rin=rin2-2--set length for 5's
    else
    rin=rin2
    end--if i=
    ---------------------------------------------------
    arc=(math.pi/180)*(210+(i*m1))
    ppx=0+rout2*(math.sin(arc))
    ppy=0-rout2*(math.cos(arc))
    arc=(math.pi/180)*(210+(i*m1))
    pix=0+rin*(math.sin(arc))
    piy=0-rin*(math.cos(arc))
    cairo_move_to (cr,px+ppx,py+ppy)
    cairo_line_to (cr,px+pix,py+piy)
    cairo_stroke (cr)
    end--for i --line drawing
    --kmh reading
    kmh={0,10,20,30,40,50,60,70,80,90}
    local rout=rin2-18
    for i=1,#kmh do
    arc=(math.pi/180)*(210+((i-1)*(m1*10)))
    ppx=0+rout*(math.sin(arc))
    ppy=0-rout*(math.cos(arc))
    text=kmh[i]
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    width=extents.width
    height=extents.height
    cairo_move_to (cr,px+ppx-(width/2),py+ppy+(height/2))
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end--kmh lines and numbers
    --knots
    --60kmh=52.1386
    cairo_set_line_width (cr,1)
    local m1=300/52.1386
    local rout3=90
    local rin3=rout3-5
    local num=50
    --print lines---------------
    for i=0,num do
    if i==0 or i==10 or i==20 or i==30 or i==40 or i==50 then
    rout=rout3-1--set length for 10s
    cairo_set_line_width (cr,3)
    elseif i==5 or i==15 or i==25 or i==35 or i==45 then
    rout=rout3+4--set length for 5's
    cairo_set_line_width (cr,1)
    else
    rout=rout3
    cairo_set_line_width (cr,1)
    end--if i=
    ---------------------------------------------------
    arc=(math.pi/180)*(210+(i*m1))
    ppx=0+rout*(math.sin(arc))
    ppy=0-rout*(math.cos(arc))
    arc=(math.pi/180)*(210+(i*m1))
    pix=0+rin3*(math.sin(arc))
    piy=0-rin3*(math.cos(arc))
    cairo_move_to (cr,px+pix,py+piy)
    cairo_line_to (cr,px+ppx,py+ppy)
    cairo_stroke (cr)
    end--for i --line drawing
    --kmh reading
    knot={0,10,20,30,40,50}
    local rout=rin3+15
    for i=1,#kmh do
    arc=(math.pi/180)*(210+((i-1)*(m1*10)))
    ppx=0+rout*(math.sin(arc))
    ppy=0-rout*(math.cos(arc))
    text=knot[i]
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    width=extents.width
    height=extents.height
    cairo_move_to (cr,px+ppx-(width/2),py+ppy+(height/2))
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end
    --scale labels
    local text="mph"
    local extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    local width=extents.width
    local height=extents.height
    cairo_move_to (cr,px-(width/2),py+rin1)
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    local text="kmh"
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    local width=extents.width
    local height=extents.height
    cairo_move_to (cr,px-(width/2),py+rin2)
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    local text="knots"
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    local width=extents.width
    local height=extents.height
    cairo_move_to (cr,px-(width/2),py+rin3)
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    local text="Wind Speed"
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    local width=extents.width
    local height=extents.height
    cairo_move_to (cr,px-(width/2),py+rin3+16)
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    --pointer
    if ws==nil then ws=0 end
    local wspd=ws
    local m1=300/60
    local m2=wspd*m1
    local rout1=rout3
    local arc=(math.pi/180)*(210+m2)
    local ppx=0+rout1*(math.sin(arc))
    local ppy=0-rout1*(math.cos(arc))
    ------------------------------
    local arc=(math.pi/180)*(210+m2+180)
    local ppox=0+rout1*(math.sin(arc))
    local ppoy=0-rout1*(math.cos(arc))
    -------------------------------
    local rin3=7
    local arc=(math.pi/180)*(210+m2-90)
    local pilx=0+rin3*(math.sin(arc))
    local pily=0-rin3*(math.cos(arc))
    local arc=(math.pi/180)*(210+m2+90)
    local pirx=0+rin3*(math.sin(arc))
    local piry=0-rin3*(math.cos(arc))
    --------------------------------
    cairo_move_to (cr,px+pilx,py+pily)
    cairo_line_to (cr,px+ppx,py+ppy)
    cairo_line_to (cr,px+pirx,py+piry)
    cairo_line_to (cr,px+pilx,py+pily)
    cairo_set_source_rgba (cr,1,0,0,1)
    cairo_fill (cr)
    cairo_arc (cr,px,py,rin3,0,(2*math.pi))
    cairo_fill (cr)
    ---------------------------------
    cairo_move_to (cr,px+pilx,py+pily)
    cairo_line_to (cr,px+ppox,py+ppoy)
    cairo_line_to (cr,px+pirx,py+piry)
    cairo_line_to (cr,px+pilx,py+pily)
    cairo_set_source_rgba (cr,1,1,1,1)
    cairo_fill (cr)
    cairo_set_source_rgba (cr,1,0,0,1)
    cairo_arc (cr,px,py,rin3,0,(2*math.pi))
    cairo_fill (cr)
    -----------------------------------
    cairo_set_source_rgba (cr,0,0,0,1)
    cairo_arc (cr,px,py,rin3-1,0,(2*math.pi))
    cairo_fill (cr)
    end--wspeed_dial function
    ------------------------------------------------------------------------------
    function humidity(x,y,hval1)
    hval=hval1*1.5
    yt=y-1
    rh=151
    rw=30
    local pat = cairo_pattern_create_linear (0,yt,0,yt+rh);
    cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 0);
    cairo_pattern_add_color_stop_rgba (pat, 0, 0, 0, 1, 1);
    cairo_rectangle (cr,x,yt,rw, rh);
    cairo_set_source (cr, pat);
    cairo_fill (cr);
    cairo_pattern_destroy (pat);
    ----------
    for i=1,11 do
    lwid=-1
    cairo_set_source_rgba (cr,1,1,1,1)
    cairo_move_to (cr,x+rw,(y+150)-((i-1)*15))
    cairo_rel_line_to (cr,lwid,0)
    cairo_stroke(cr)
    end
    ----------
    cairo_set_source_rgba (cr,1,1,1,1)
    hh=5
    hw1=19
    hw2=hw1+10
    if hval==nil then hval=0 end
    tx,ty=x+hw1,(y+150)-(hval+hh)
    ix,iy=x+hw2,(y+150)-hval
    bx,by=x+hw1,(y+150)-(hval-hh)
    cairo_move_to (cr,tx,ty)
    cairo_line_to (cr,ix,iy)
    cairo_line_to (cr,bx,by)
    cairo_line_to (cr,tx,ty)
    cairo_fill (cr)
    cairo_set_source_rgba (cr,1,1,1,1)
    font="Mono"
    fsize=12
    cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, fsize)
    cairo_move_to (cr,x+hw2+3,(y+150)-(hval-hh))
    cairo_show_text (cr,hval1.."%")
    cairo_stroke (cr)
    label="Relative Humidity"
    cairo_move_to (cr,x+12,y+150)
    cairo_rotate (cr,(math.pi/180)*(-90))
    cairo_show_text (cr,label)
    cairo_stroke (cr)
    cairo_rotate (cr,(math.pi/180)*(90))
    end--humidity
    ------------------------------------------------------------------------------
    function txt(text,xpos,ypos,font,fsize,red,green,blue,alpha)
    cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, fsize)
    cairo_set_source_rgba (cr,red,green,blue,alpha)
    cairo_move_to (cr,xpos,ypos)
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end--function txt
    ------------------------------------------------------------------------------
    function compass(wx,wy,rout,wdeg,w,wg)
    local rin=rout-((rout/100)*10)
    cairo_set_source_rgba (cr,0.1,0.1,0.1,1)
    cairo_arc (cr,wx,wy,rout,0,(2*math.pi))
    cairo_fill (cr)
    cairo_set_source_rgba (cr,1,1,1,1)
    cairo_arc (cr,wx,wy,rout,0,(2*math.pi))
    cairo_stroke (cr)
    for i=1,36 do
    arc=(math.pi/180)*(i*10)
    wpx=0+rout*(math.sin(arc))
    wpy=0-rout*(math.cos(arc))
    arc=(math.pi/180)*(i*10)
    wix=0+rin*(math.sin(arc))
    wiy=0-rin*(math.cos(arc))
    cairo_move_to (cr,wx+wpx,wy+wpy)
    cairo_line_to (cr,wx+wix,wy+wiy)
    cairo_stroke (cr)
    end
    --print directions
    local font="Mono"
    local fsize=10
    cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, fsize)
    dirs={"N","NE","E","SE","S","SW","W","NW"}
    local rdir=rout-((rout/100)*25)
    for i=1,8 do
    arc=(math.pi/180)*((i-1)*(360/8))
    wdx=0+rdir*(math.sin(arc))
    wdy=0-rdir*(math.cos(arc))
    text=dirs[i]
    extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    width=extents.width
    height=extents.height
    cairo_move_to (cr,wx+wdx-(width/2),wy+wdy+(height/2))
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end
    --indicator
    local npr=rout-((rout/100)*15)
    if wdeg==nil then wdeg=0 end
    local arc=(math.pi/180)*(wdeg)
    local npx=0+npr*(math.sin(arc))
    local npy=0-npr*(math.cos(arc))
    cairo_move_to (cr,wx+npx,wy+npy)
    local nprm=rout-((rout/100)*88)
    local arc=(math.pi/180)*(wdeg+90)
    local npmrx=0+nprm*(math.sin(arc))
    local npmry=0-nprm*(math.cos(arc))
    local arc=(math.pi/180)*(wdeg-90)
    local npmlx=0+nprm*(math.sin(arc))
    local npmly=0-nprm*(math.cos(arc))
    cairo_line_to (cr,wx+npmrx,wy+npmry)
    cairo_line_to (cr,wx+npmlx,wy+npmly)
    cairo_line_to (cr,wx+npx,wy+npy)
    cairo_set_source_rgba (cr,1,0,0,1)
    cairo_fill (cr)
    cairo_set_source_rgba (cr,1,1,1,1)
    ---------------------------------
    local arc=(math.pi/180)*(wdeg-180)
    local spx=0+npr*(math.sin(arc))
    local spy=0-npr*(math.cos(arc))
    cairo_move_to (cr,wx+spx,wy+spy)
    local sprm=nprm
    local arc=(math.pi/180)*(wdeg+90-180)
    local spmrx=0+sprm*(math.sin(arc))
    local spmry=0-sprm*(math.cos(arc))
    local arc=(math.pi/180)*(wdeg-90-180)
    local spmlx=0+sprm*(math.sin(arc))
    local spmly=0-sprm*(math.cos(arc))
    cairo_line_to (cr,wx+spmrx,wy+spmry)
    cairo_line_to (cr,wx+spmlx,wy+spmly)
    cairo_line_to (cr,wx+spx,wy+spy)
    cairo_fill (cr)
    --------------------------------------
    cairo_set_source_rgba (cr,0,0,0,1)
    cairo_arc (cr,wx,wy,nprm,0,(2*math.pi))
    cairo_fill (cr)
    cairo_set_source_rgba (cr,1,0,0,1)
    cairo_arc (cr,wx,wy,nprm,0,(2*math.pi))
    cairo_stroke (cr)
    ------------------------
    cairo_set_source_rgba (cr,1,1,1,1)
    local text="Wind Direction"
    local extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    local width=extents.width
    local height=extents.height
    cairo_move_to (cr,wx-(width/2),wy-rout-5)
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end--compass
    ------------------------------------------------------------------------------
    function thermometer(mx,my,temp,label,scale,mid,units)
    --by mrpeachy 2011
    if scale==nil then scale=1 end
    if units=="F" then height=150 elseif units=="C" then height=160 end
    local mx=mx*(1/scale)
    local my=my*(1/scale)
    local font="Mono"
    local fsize=10
    cairo_scale (cr,scale,scale)
    cairo_set_line_width (cr,1)
    cairo_set_source_rgba (cr,1,1,1,1)
    --graphics outer
    --bottom circle
    r_outer=25
    local lang_outer=335
    local rang_outer=0+(360-lang_outer)
    local h_outer=height-4--maybe make this a percentage?###########
    cairo_arc (cr,mx,my,r_outer,(math.pi/180)*(rang_outer-90),(math.pi/180)*(lang_outer-90))
    --coordinates,left line
    local arc=(math.pi/180)*lang_outer
    local lxo=0+r_outer*(math.sin(arc))
    local lyo=0-r_outer*(math.cos(arc))
    cairo_line_to (cr,mx+lxo,my+lyo-h_outer)
    --coordinates,left line
    local arc=(math.pi/180)*rang_outer
    local rxo=0+r_outer*(math.sin(arc))
    local ryo=0-r_outer*(math.cos(arc))
    --top circle
    cairo_arc (cr,mx+lxo+((rxo-lxo)/2),my+lyo-h_outer,(rxo-lxo)/2,(math.pi/180)*(270-90),(math.pi/180)*(90-90))
    --right line
    cairo_line_to (cr,mx+lxo+((rxo-lxo)),my+lyo)
    cairo_stroke (cr)
    ----------------------------------------------
    --graphics inner
    --####################################################
    if units=="F" then
    local str,stg,stb,sta=0,1,1,1
    local mr,mg,mb,ma=1,1,0,1
    local fr,fg,fb,fa=1,0,0,1
    local nd=150
    if temp==nil then temp=0 end
    local tadj=temp+30
    local middle=mid+30
    if tadj<(middle) then
    colr=((mr-str)*(tadj/(middle)))+str
    colg=((mg-stg)*(tadj/(middle)))+stg
    colb=((mb-stb)*(tadj/(middle)))+stb
    cola=((ma-sta)*(tadj/(middle)))+sta
    elseif tadj>=(middle) then
    colr=((fr-mr)*((tadj-(middle))/(nd-middle)))+mr
    colg=((fg-mg)*((tadj-(middle))/(nd-middle)))+mg
    colb=((fb-mb)*((tadj-(middle))/(nd-middle)))+mb
    cola=((fa-ma)*((tadj-(middle))/(nd-middle)))+ma
    end
    cairo_set_source_rgba (cr,colr,colg,colb,cola)
    --bottom circle
    r_inner=r_outer-6
    local lang_inner=lang_outer+9
    local rang_inner=0+(360-lang_inner)
    local h_inner=temp+30
    cairo_arc (cr,mx,my,r_inner,(math.pi/180)*(rang_inner-90),(math.pi/180)*(lang_inner-90))
    --coordinates,left line
    local arc=(math.pi/180)*lang_inner
    lxi=0+r_inner*(math.sin(arc))
    local lyi=0-r_inner*(math.cos(arc))
    cairo_line_to (cr,mx+lxi,my+lyi-h_inner)
    --coordinates,left line
    local arc=(math.pi/180)*rang_inner
    rxi=0+r_inner*(math.sin(arc))
    local ryi=0-r_inner*(math.cos(arc))
    --top circle
    cairo_arc (cr,mx+lxi+((rxi-lxi)/2),my+lyi-h_inner,(rxi-lxi)/2,(math.pi/180)*(270-90),(math.pi/180)*(90-90))
    --right line
    cairo_line_to (cr,mx+lxi+((rxi-lxi)),my+lyi)
    cairo_fill (cr)
    ----------------------------
    if label~="none" then
    --scale lines
    cairo_set_line_width (cr,1)
    cairo_set_source_rgba (cr,1,1,1,0.5)
    local grad=10
    local lnn=15
    local lnx=mx+lxo
    local lnw=(rxo-lxo)
    for i=1,lnn do
    lny=my-r_inner-(10+((i-1)*grad))-((rxi-lxi)/2)
    if i==lnn then
    lnx=lnx+2
    lnw=lnw-4
    end
    cairo_move_to (cr,lnx,lny)
    cairo_rel_line_to (cr,lnw,0)
    cairo_stroke (cr)
    end
    --numbers
    cairo_set_source_rgba (cr,1,1,1,1)
    cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, fsize)
    local grad=20
    local lnn=8
    local lnx=mx+lxo+(rxo-lxo)+4
    num={-20,"0°"..units,20,40,60,80,100,120}
    for i=1,lnn do
    lny=my-r_inner-(10+((i-1)*grad))-((rxi-lxi)/2)+(fsize/3)
    cairo_move_to (cr,lnx,lny)
    cairo_show_text (cr,num[i])
    cairo_stroke (cr)
    end
    end--if label=none
    end--if units=F
    --#################################################
    if units=="C" then
    --from -30 to 50 C
    local str,stg,stb,sta=0,1,1,1
    local mr,mg,mb,ma=1,1,0,1
    local fr,fg,fb,fa=1,0,0,1
    local nd=160
    if temp==nil then temp=0 end
    local tadj=(temp*2)+60
    local middle=(mid*2)+60
    if tadj<(middle) then
    colr=((mr-str)*(tadj/(middle)))+str
    colg=((mg-stg)*(tadj/(middle)))+stg
    colb=((mb-stb)*(tadj/(middle)))+stb
    cola=((ma-sta)*(tadj/(middle)))+sta
    elseif tadj>=(120) then
    colr=((fr-mr)*((tadj-(middle))/(nd-middle)))+mr
    colg=((fg-mg)*((tadj-(middle))/(nd-middle)))+mg
    colb=((fb-mb)*((tadj-(middle))/(nd-middle)))+mb
    cola=((fa-ma)*((tadj-(middle))/(nd-middle)))+ma
    end
    cairo_set_source_rgba (cr,colr,colg,colb,cola)
    --cairo_set_source_rgba (cr,0,1,1,1)
    --bottom circle
    r_inner=r_outer-6
    local lang_inner=lang_outer+9
    local rang_inner=0+(360-lang_inner)
    local h_inner=(temp*2)+60
    cairo_arc (cr,mx,my,r_inner,(math.pi/180)*(rang_inner-90),(math.pi/180)*(lang_inner-90))
    --coordinates,left line
    local arc=(math.pi/180)*lang_inner
    lxi=0+r_inner*(math.sin(arc))
    local lyi=0-r_inner*(math.cos(arc))
    cairo_line_to (cr,mx+lxi,my+lyi-h_inner)
    --coordinates,left line
    local arc=(math.pi/180)*rang_inner
    rxi=0+r_inner*(math.sin(arc))
    local ryi=0-r_inner*(math.cos(arc))
    --top circle
    cairo_arc (cr,mx+lxi+((rxi-lxi)/2),my+lyi-h_inner,(rxi-lxi)/2,(math.pi/180)*(270-90),(math.pi/180)*(90-90))
    --right line
    cairo_line_to (cr,mx+lxi+((rxi-lxi)),my+lyi)
    cairo_fill (cr)
    ----------------------------
    if label~="none" then
    --scale lines
    cairo_set_line_width (cr,1)
    cairo_set_source_rgba (cr,1,1,1,0.5)
    local grad=10
    local lnn=17
    local lnx=mx+lxo
    local lnw=(rxo-lxo)
    for i=1,lnn do
    lny=my-r_inner-(((i-1)*grad))-((rxi-lxi)/2)
    if i==lnn then
    lnx=lnx+2
    lnw=lnw-4
    end
    cairo_move_to (cr,lnx,lny)
    cairo_rel_line_to (cr,lnw,0)
    cairo_stroke (cr)
    end
    --numbers
    cairo_set_source_rgba (cr,1,1,1,1)
    cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, fsize)
    local grad=20
    local lnn=9
    local lnx=mx+lxo+(rxo-lxo)+4
    num={-30,-20,-10,"0°"..units,10,20,30,40,50}
    for i=1,lnn do
    lny=my-r_inner-(((i-1)*grad))-((rxi-lxi)/2)+(fsize/3)
    cairo_move_to (cr,lnx,lny)
    cairo_show_text (cr,num[i])
    cairo_stroke (cr)
    end
    end--if label=none
    end--if units=C
    --#################################################
    --label
    if label~="none" then
    local font="Mono"
    local fsize=12
    cairo_select_font_face (cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, fsize)
    local lbx=mx+lxo-5
    local lby=my-r_inner-10-((rxi-lxi)/2)
    cairo_move_to (cr,lbx,lby)
    cairo_rotate (cr,(math.pi/180)*(-90))
    cairo_show_text (cr,label)
    cairo_stroke (cr)
    cairo_rotate (cr,(math.pi/180)*(90))
    --temperature readout
    cairo_set_source_rgba (cr,0,0,0,1)
    local text=temp.."°"..units
    local extents=cairo_text_extents_t:create()
    cairo_text_extents(cr,text,extents)
    local width=extents.width
    local height=extents.height
    cairo_move_to (cr,mx-(width/2),my+(height/2))
    cairo_show_text (cr,text)
    cairo_stroke (cr)
    end--if label
    ------------------------------------
    cairo_scale (cr,1/scale,1/scale)
    end--thermometer function
    ------------------------------------------------------------------------------
    function conky_draw_bg(r,x,y,w,h,color,alpha)
    if conky_window == nil then return end
    if cs == nil then cairo_surface_destroy(cs) end
    if cr == nil then cairo_destroy(cr) end
    local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
    local cr = cairo_create(cs)
    cairo_set_source_rgba (cr,htm2col(color,alpha))
    --top left mid circle
    local xtl=x+r
    local ytl=y+r
    --top right mid circle
    local xtr=(x+r)+((w)-(2*r))
    local ytr=y+r
    --bottom right mid circle
    local xbr=(x+r)+((w)-(2*r))
    local ybr=(y+r)+((h)-(2*r))
    --bottom right mid circle
    local xbl=(x+r)
    local ybl=(y+r)+((h)-(2*r))
    -----------------------------
    cairo_move_to (cr,xtl,ytl-r)
    cairo_line_to (cr,xtr,ytr-r)
    cairo_arc(cr,xtr,ytr,r,((2*math.pi/4)*3),((2*math.pi/4)*4))
    cairo_line_to (cr,xbr+r,ybr)
    cairo_arc(cr,xbr,ybr,r,((2*math.pi/4)*4),((2*math.pi/4)*1))
    cairo_line_to (cr,xbl,ybl+r)
    cairo_arc(cr,xbl,ybl,r,((2*math.pi/4)*1),((2*math.pi/4)*2))
    cairo_line_to (cr,xtl-r,ytl)
    cairo_arc(cr,xtl,ytl,r,((2*math.pi/4)*2),((2*math.pi/4)*3))
    cairo_close_path(cr)
    cairo_fill (cr)
    -----------------------------
    cairo_surface_destroy(cs)
    cairo_destroy(cr)
    return ""
    end-- conky_draw_bg function

--[[ htm2col()
 Parse a HTML-colour + return lua/cairo-suitable colours.
 This function parses colours like 0xrrggbb + alpha in the range [0, 1]
 For example, htm2col(0x00ff00,1.0) would return 0, 1, 0, 1.
 obtained from clock_rings

 @param colour The colour to parse eg 0xffffff (white)
 @param alpha  The alpha  to parse eg 0.5
 @return 4 values which each are in the range [0, 1].
]]
function htm2col(colour,alpha)
   return ((colour / 0x10000) % 0x100) / 255., ((colour / 0x100) % 0x100) / 255., (colour % 0x100) / 255., alpha
end

 ------------------------------------------------------------------------------
function conky_draw_test()
   if conky_window==nil then return end
   local cs=cairo_xlib_surface_create(conky_window.display,conky_window.drawable,conky_window.visual,conky_window.width,conky_window.height)
   local cr=cairo_create(cs)
   local date=conky_parse('${execi 300 /home/alexk/.conky/weather.pl EGNX DATE}')
   local pressure=conky_parse('${execi 300 /home/alexk/.conky/weather.pl EGNX ALT_HP}')
   pressure=tonumber(pressure)
   local time=conky_parse('${execi 300 /home/alexk/.conky/weather.pl EGNX TIME}')
   local location=conky_parse('${execi 300 /home/alexk/.conky/weather.pl EGNX CSV}')
   local datetime=date.." "..time
-- local pressure=tonumber(conky_parse('${weather http://weather.noaa.gov/pub/data/observations/metar/stations/ EGNX pressure 30}'))

   -- check all local are NOT nil
   if date==nil then
      print("date is nil in conky_draw_test()")
      return
   end
   if pressure==nil then
      print("pressure is nil in conky_draw_test()")
      return
   end
   if time==nil then
      print("time is nil in conky_draw_test()")
      return
   end
   if location==nil then
      print("location is nil in conky_draw_test()")
      return
   end

   -- update CSV file only if barometer pressure has changed
   if old_pressure==nil or old_pressure<1 then
      update=1
   else
      if old_pressure==pressure then update=0 else update=1 end
   end

   barometer(cr,pressure,120,150)
   if update==1 then
      savecsv(datetime,location,pressure)
      old_pressure=pressure
   end
   -----------------------------
   cairo_surface_destroy(cs)
   cairo_destroy(cr)
   return ""
end-- function conky_draw_test

Online

#6 2023-12-03 22:46:08

alexkemp
Member
Registered: 2018-05-14
Posts: 292  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

The NOAA keep changing the access methods for weather access from the airport of your choice. I therefore place the access method into a PERL script together with caching (to substantially reduce the hammer from these scripts on the chosen Airport). Here is the latest script (although the Id has NOT yet been updated) (23:06: just updated):

~/.conky/weather.pl:

#!/usr/bin/perl

# $Id: weather.pl,v 1.3 2023/10/17 14:23:49 +0100 alexkemp Exp $

# Brief Description
# =================
#
# utility to replace conky weather using aviationweather.gov (US Govt)
# conky weather stopped working 2016 August
# (weather.noaa.gov/pub/data/observations/metar/stations/ withdrawn)
#
# Given an airport site code on the command line, weather.pl
# fetches the weather and displays it on the command-line.

# Requires libgeo-metar-perl
#          (and others)

# Here are some example airports:
# East Midlands : EGNX
# LA            : KLAX
# Dallas        : KDFW
# Detroit       : KDTW
# Chicago       : KMDW
#
# 2023-10-16 v 1.3 url update following aviationweather.gov site update
# 2020-11-19 v 1.2   added $DATE + $CSV (store barometer csv)
#                  changed $ERR to "" (empty string)
#                  changed order: check cache timeout first (reduce remote accesses)
# 2018-05-02 v 1.1   added file caching (reduce hammer on remote site)
# 2016-09-18 v 1.0 started

my $HELP = "
USAGE:   $0 <locationCode> <responseType>
  example: $0 EGNX ALT_HP
           (East Midlands for barometer-in-mbar)

list of location codes:
  http://weather.rap.ucar.edu/surface/stations.txt
METAR source code:
  http://jeremy.zawodny.com/perl/Geo-METAR/METAR.html

list of possible responses (date_time: 2020/11/08 22:20):
  ALT          (eg '30.061522694'     inches)
  ALT_HP       (eg '1018'          millibars)
  CSV          (eg '~/.conky/barometer.csv' )
  DATE         (eg '2020-11-08'          UTC)
  DEW_C        (eg '11'       temperature °C)
  DEW_F        (eg '51.8'     temperature °F)
  RH           (eg '100' relative humidity %)
  SKY          (eg 'Sky Clear'              )
  TEMP_C       (eg '11'       temperature °C)
  TEMP_F       (eg '51.8'     temperature °F)
  TIME         (eg '22:20 UTC'              )
  TYPE         (eg 'Routine Weather Report' )
  VISIBILITY   (eg '0600 meters'            )
  WEATHER      (eg 'No significant weather' )
  WIND_DIR_ABB (eg 'S'                      )
  WIND_DIR_DEG (eg '170'                    )
  WIND_DIR_ENG (eg 'South'                  )
  WIND_KTS     (eg '03'          knots      )
  WIND_MPH     (eg '3.45233835'  mph        )
  WIND_MS      (eg '1.543333332' m/sec      )
  WIND_VAR     (eg ''                       )
  METAR        (eg 'EGNX 082220Z 17003KT 0600 R27/P1500 RA FG BKN002 OVC010 11/11 Q1018')

Version: v1.3 2023-10-16\n";

# remote site(s) providing metar info
my $REMOTE = "https://aviationweather.gov/api/data/metar";
#my $REMOTE = "https://www.aviationweather.gov/metar/data";
#my $REMOTE = "https://tgftp.nws.noaa.gov/data/observations/metar/stations";
# Get the site code requested
my ($LOCATION,$TYPE) = @ARGV;
# cache parameters
# file location
my $CACHE = "~/.conky/.metar_cache";
# update interval, secs
my $CACHE_UI = 1200;
# file location
my $CSV = "~/.conky/barometer.csv";

die $HELP unless ($LOCATION && $TYPE);

# Get the modules we need.
use strict;
use utf8;
use Capture::Tiny ':all';
use Date::Calc ':all';
use Geo::METAR;
use LWP::UserAgent;
use POSIX qw(strftime);
use Switch;
use Time::Local;

# expand the tilde (file-open will NOT auto-expand it)
$CACHE =~ s{ ^ ~ ( [^/]* ) }
           { $1
              ? (getpwnam($1))[7]
              : ($ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7])
           }ex;
# hash array
my %CACHE_HASH;
# expand the tilde (file-open will NOT auto-expand it)
$CSV =~ s{ ^ ~ ( [^/]* ) }
         { $1
            ? (getpwnam($1))[7]
            : ($ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7])
         }ex;
# get cache-file mod timestamp + time-now (secs since Epoch)
my $NOW = time();
my $CACHE_MTIME = (stat $CACHE)[9];
my $SKY;
my $WEATHER;
my $tmp;
my $ERR = "";

if(!$CACHE_MTIME) {
   # cache is removed
	# create value that will cause file re-create
   $CACHE_MTIME = $NOW - $CACHE_UI - 1;
}
# 2020-10-17 $REMOTE url has changed yet again
#            $data re is now failing, so we switch to $response->decoded_content
# 2020-11-19 change order to check cache timeout first
#            this is to save many HEAD-checks on remote
# if cache has timed out then refresh the cache from remote
# else provide response from cache
if(($NOW - $CACHE_UI) > $CACHE_MTIME) { # cache has timed-out
   # update cache from remote unless remote site unavailable
   # first a HEAD request to make sure site is up
   my $ua = new LWP::UserAgent;
   my $req = new HTTP::Request HEAD => "$REMOTE?ids=$LOCATION";
   #my $req = new HTTP::Request HEAD => "$REMOTE/$LOCATION.TXT";
   my $response = $ua->request($req);
   if($response->is_success) { # true; remote site is responding
# print "\$REMOTE?ids=\$LOCATION=$REMOTE?ids=$LOCATION\n";
# print $response->headers()->as_string;
      # aviationweather.gov does not send Last-Modified (tsk tsk)
      # tgftp.nws.noaa.gov DOES send Last-Modified

      # refresh local cache from remote site
      # get the remote data and find the METAR.
      my $ua = new LWP::UserAgent;
      my $req = new HTTP::Request GET => "$REMOTE?ids=$LOCATION";
      #my $req = new HTTP::Request GET => "$REMOTE/$LOCATION.TXT";
      my $response = $ua->request($req);

      if($response->is_success) {
         # get the data and find the METAR.
         my $m = new Geo::METAR;
         my $data = $response->decoded_content;
         my $METAR = $data;
#         my $data = $response->as_string;      # grab response
#         $data =~ s/\n//go;                    # remove newlines
#         $data =~ m/($LOCATION\s\d+Z.*?)</go;  # find the METAR string
#         my $METAR = $1;                       # keep it

         # Sanity check
         if( length( $METAR ) < 10 ) {
            die "METAR is too short! Something went wrong.";
         }

         # pass the data to the METAR module.
         $m->metar($METAR);
# $m->dump;
         #
         # $m->SKY, $m->WEATHER + $m->WEATHER_LOG are arrays
         # (see https://idefix.net/~koos/perl/Geo-METAR/METAR.html)
         # DUMP shows 1st array, but a bug affects each individual access
         my $stdout = capture_stdout { $m->dump; };
         $stdout =~ /SKY: (.*)/;         # find the SKY string
         $SKY = $1;                      # keep it
         $stdout =~ /WEATHER: (.*)/;     # find the WEATHER string
         $WEATHER = $1;                  # keep it
         #
         # Relative Humidity (RH) (accurate for RH > 50%)
         # https://en.wikipedia.org/wiki/Dew_point#Simple_approximation
         # 100 - 5*(TEMP_C - DEW_C)
         # 100*(6.1094^((17.625*TD)/(243.04+TD))/6.1094^((17.625*T)/(243.04+T))) ??
         my $RH = 100 - (5*($m->TEMP_C - $m->DEW_C));
         #
         # handle midnight (METAR-day may actually be yesterday):
         my $DATE;
         my $gmt = 1;                      # true
         my ($year,$month,$today) = Today($gmt);
         my $day = $m->DATE;               # actually UTC day of month, 2-digits
         if($day != $today) {              # METAR-day is yesterday
            ($year,$month,$day) = Add_Delta_Days($year,$month,$today, -1);
            $DATE = "$year-$month-$day";
         } else {
            $DATE = strftime "%F", gmtime; # ISO 8601 GMT/UTC date (YYYY-MM-DD, no DST)
         }
         $CACHE_HASH{'ALT'         } = $m->ALT;
         $CACHE_HASH{'ALT_HP'      } = $m->ALT_HP;
         $CACHE_HASH{'CSV'         } = $CSV;
         $CACHE_HASH{'DATE'        } = $DATE;
         $CACHE_HASH{'DEW_C'       } = $m->DEW_C;
         $CACHE_HASH{'DEW_F'       } = $m->DEW_F;
         $CACHE_HASH{'SKY'         } = $SKY;
         $CACHE_HASH{'RH'          } = $RH;
         $CACHE_HASH{'TEMP_C'      } = $m->TEMP_C;
         $CACHE_HASH{'TEMP_F'      } = $m->TEMP_F;
         $CACHE_HASH{'TIME'        } = $m->TIME;
         $CACHE_HASH{'TYPE'        } = $m->TYPE;
         $CACHE_HASH{'VISIBILITY'  } = $m->VISIBILITY;
         $CACHE_HASH{'WEATHER'     } = $WEATHER;
         $CACHE_HASH{'WIND_DIR_ABB'} = $m->WIND_DIR_ABB;
         $CACHE_HASH{'WIND_DIR_DEG'} = $m->WIND_DIR_DEG;
         $CACHE_HASH{'WIND_DIR_ENG'} = $m->WIND_DIR_ENG;
         $CACHE_HASH{'WIND_KTS'    } = $m->WIND_KTS;
         $CACHE_HASH{'WIND_MPH'    } = $m->WIND_MPH;
         $CACHE_HASH{'WIND_MS'     } = $m->WIND_MS;
         $CACHE_HASH{'WIND_VAR'    } = $m->WIND_VAR;
         $CACHE_HASH{'METAR'       } = $m->METAR;
         # Some result array values may contain errors of indeterminate length. Each is
         # checked & placed in a hash for current & future access via file.
         for(keys %CACHE_HASH) {
            $tmp = $CACHE_HASH{$_};
            if($tmp =~ m/error/i)    { $CACHE_HASH{$_} = $ERR; }
         if(ref($tmp) eq "ARRAY") { $CACHE_HASH{$_} = $ERR; }
         }
#print "dumping contents of \$m:\n";
#$m->dump;
#print "dump complete.\n\n";

         # store $CACHE_HASH built from remote into cache
         use Storable qw( nstore_fd );
         use Fcntl qw(:DEFAULT :flock);
         sysopen( DF, $CACHE, O_RDWR|O_CREAT, 0666) 
            or die "can't open $CACHE: $!";
         flock( DF, LOCK_EX)
            or die "can't lock $CACHE: $!";
         nstore_fd( \%CACHE_HASH, *DF )
            or die "can't store hash\n";
         truncate( DF, tell( DF ));
         close( DF );
      } else { #  if($response->is_success) (GET succeeded)
         print $response->error_as_HTML;
         my $err_msg = $response->error_as_HTML;
         warn "$err_msg\n\n";
         die "$!";
		} #  if($response->is_success) else
   } #  if($response->is_success) (HEAD succeeded)
} else { # if(($NOW - $CACHE_UI) > $CACHE_MTIME) cache has timed-out
   # use local cache of remote site
   use Storable qw( fd_retrieve );
   use Fcntl qw(:DEFAULT :flock);
   open(DF, "< $CACHE")
	   or die "can't open $CACHE: $!";
   flock(DF, LOCK_SH)
	   or die "can't lock $CACHE: $!";
   %CACHE_HASH = %{ fd_retrieve(*DF)};
   close(DF);
} # if(($NOW - $CACHE_UI) > $CACHE_MTIME) else

#for(keys %CACHE_HASH) {
#	print "$_ = $CACHE_HASH{$_}\n";
#}

switch ($TYPE) {
   case "ALT"          { print $CACHE_HASH{'ALT'         };}
   case "ALT_HP"       { print $CACHE_HASH{'ALT_HP'      };}
   case "CSV"          { print $CACHE_HASH{'CSV'         };}
   case "DATE"         { print $CACHE_HASH{'DATE'        };}
   case "DEW_C"        { print $CACHE_HASH{'DEW_C'       };}
   case "DEW_F"        { print $CACHE_HASH{'DEW_F'       };}
   case "SKY"          { print $CACHE_HASH{'SKY'         };}
   case "RH"           { print $CACHE_HASH{'RH'          };}
   case "TEMP_C"       { print $CACHE_HASH{'TEMP_C'      };}
   case "TEMP_F"       { print $CACHE_HASH{'TEMP_F'      };}
   case "TIME"         { print $CACHE_HASH{'TIME'        };}
   case "TYPE"         { print $CACHE_HASH{'TYPE'        };}
   case "VISIBILITY"   { print $CACHE_HASH{'VISIBILITY'  };}
   case "WEATHER"      { print $CACHE_HASH{'WEATHER'     };}
   case "WIND_DIR_ABB" { print $CACHE_HASH{'WIND_DIR_ABB'};}
   case "WIND_DIR_DEG" { print $CACHE_HASH{'WIND_DIR_DEG'};}
   case "WIND_DIR_ENG" { print $CACHE_HASH{'WIND_DIR_ENG'};}
   case "WIND_KTS"     { print $CACHE_HASH{'WIND_KTS'    };}
   case "WIND_MPH"     { print $CACHE_HASH{'WIND_MPH'    };}
   case "WIND_MS"      { print $CACHE_HASH{'WIND_MS'     };}
   case "WIND_VAR"     { print $CACHE_HASH{'WIND_VAR'    };}
   else                { print $CACHE_HASH{'METAR'       };}
} # switch ($TYPE)

exit;

__END__

Last edited by alexkemp (2023-12-03 23:06:33)

Online

#7 2023-12-03 22:49:27

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Redundant post, issue solved, conserving site resources. wink

Last edited by greenjeans (2023-12-06 01:44:23)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#8 2023-12-03 23:11:29

alexkemp
Member
Registered: 2018-05-14
Posts: 292  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

greenjeans wrote:

FYI MATE weather (part of the clock preferences) doesn't work and hasn't in some time

I appreciate that you haven't read all the scripts.

What I've posted *does* work, and all in one call. I do NOT use the CONKY calls. I've written my own PERL script and that collects all stats in one call, put them into a cache, and then collects from the cache on every call until refreshed.

Online

#9 2023-12-04 00:52:18

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Redundant post, issue solved, conserving site resources. wink

Last edited by greenjeans (2023-12-06 01:44:52)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#10 2023-12-04 01:10:51

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Oh and while talking conky, another little tidbit:

I use the Exaile music player, it's my favorite, not too complex, does internet radio and seamlessly integrates with streamripper. It's not in the repo so i'm likely the only user, lol, but if you do, it works with conky, it's not on the list of music/media players that conky works with, but it does work. Here's my lines, all I want it to do is display artist name and track but i'm sure you could add more if desired:

${if_running exaile}${font BankGothic Md BT:pixelsize=14}now playing :  ${execi 10 exaile --get-title}  –  ${execi 10 exaile --get-artist}$endif

I put it at the bottom of the display, since when it's not running that line closes up to the one above, if you stick it between sections somewhere it has to add a new line and that freaks conky out sometimes.

9y9a4o.png

Last edited by greenjeans (2023-12-04 01:13:26)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#11 2023-12-04 03:02:32

fsmithred
Administrator
Registered: 2016-11-25
Posts: 2,427  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Hint: "\n" means newline.

$ curl wttr.in/Miner?format="Condition:+%C\nTemperature:+%t\n"
Condition: Overcast
Temperature: -2°C

Offline

#12 2023-12-04 04:00:22

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Redundant post, issue solved, conserving site resources. wink

Last edited by greenjeans (2023-12-06 01:45:17)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#13 2023-12-04 04:38:28

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Redundant post, issue solved, conserving site resources. wink

Last edited by greenjeans (2023-12-06 01:46:01)


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#14 2023-12-04 11:33:06

nixer
Member
From: North Carolina, USA
Registered: 2016-11-30
Posts: 187  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

I use the Exaile music player, ... It's not in the repo

Maybe not yet.
But it has been added to the testing/ceres repo.

Offline

#15 2023-12-04 15:48:31

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Thanks nixer, that's good news!


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

#16 2023-12-05 09:27:44

alexkemp
Member
Registered: 2018-05-14
Posts: 292  

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Online

#17 2023-12-06 01:42:46

greenjeans
Member
Registered: 2017-04-07
Posts: 506  
Website

Re: [SOLVED] Weather display in conky, a simple one-line-of-code solution

Updated original post to detail the solution.


https://sourceforge.net/projects/vuu-do/
Vuu-do GNU/Linux, minimal Devuan-based openbox systems to build on, maximal versions if you prefer your linux fully-loaded.

Please donate to support Devuan and init freedom! https://devuan.org/os/donate

Offline

Board footer