前ふり
Ubuntu 18.10 にアップグレードした時に困ったこととして、アナログ時計アプリ cairo clock のパッケージが無くなってしまったこと。デジタル時計アプリは幾つかパッケージが有るけれど、アナログ時計は意外と少ない。もちろん古くから有る xclock は残っているが、これはウィンドウ枠やタイトルが消さない。
そんなわけで定番システム・モニター conky でアナログ時計を表示させることとしたのを機に、conky の設定を晒す。
設定を晒すだけなので、設定内容の意味はググって。
私のデスク・トップ
幾つかの Gnome Extension を入れて標準状態と異なっているが、conky の描画部分はデスク・トップ右上部。
表示しているのは
- 今日、明日、明後日の天気予報 (現在地に出来れば良いが、やり方が不明なので URL 直打ち)
- 直近 3 つの地震
- アナログ時計
- 先月、今月、来月のカレンダー
- CPU の温度と使用量
- メモリー使用量
- CPU 負荷トップ 5 のプロセス
- ディスク使用量とディスク・アクセス
- ネットワーク状況 (Wi-Fi 時はアクセスポイント)
準備
(2022/09/06 更新)
Ubuntu 標準の conky だと、テキスト情報をしか載せられないので、アナログ時計が表示できないので、次のパッケージをインストール。ウェブデータの取得には Python 使う。
sudo apt install -y conky-all python3-bs4
~/.config/conky/conky.conf
conky の設定ファイルは以前 ~/.conkyrc だったが最近はこちら。
conky.config で始まる部分が全体の設定で、conky.text で始まる部分が表示する項目。
少し変わった設定をしているのは
conky.config = {
alignment = 'top_left',
background = true,
border_width = 1,
cpu_avg_samples = 4,
default_color = 'black',
default_outline_color = 'white',
default_shade_color = 'white',
draw_borders = false,
draw_graph_borders = true,
draw_outline = false,
draw_shades = false,
use_xft = true,
gap_x = 1565,
gap_y = 40,
maximum_width = 350,
minimum_width = 5,
minimum_height = 5,
net_avg_samples = 4,
no_buffers = true,
out_to_console = false,
out_to_stderr = false,
extra_newline = false,
own_window = true,
own_window_class = 'Conky',
own_window_type = 'desktop',
stippled_borders = 0,
update_interval = 1.0,
uppercase = false,
use_spacer = 'none',
show_graph_scale = false,
show_graph_range = false,
double_buffer = true,
override_utf8_locale = true,
font = 'Ricty Diminished:style=Regular:size=12',
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
own_window_transparent = true,
own_window_argb_visual = true,
text_buffer_size = 512,
lua_load = '~/bin/conky/clock.lua',
lua_draw_hook_post = 'cairo_clock',
};
conky.text = [[
${execi 600 ~/bin/conky/weather.py }
$hr
${execi 600 ~/bin/conky/earthquake.sh }
$hr
${execi 600 ~/bin/conky/ncal3.sh }
$hr
CPU: ${execi 1 cat /sys/class/thermal/thermal_zone0/temp | awk '{printf("%.1f°C", ($1=$1 / 1000))}'} ${cpu cpu0}% ${color 880000}${cpubar cpu0}${color black}
${cpugraph cpu0 40,0 000088 000088}
RAM: $mem/$memmax $memperc% ${color 880000}${membar}${color black}
Swap: $swap/$swapmax $swapperc% ${color 880000}${swapbar}${color black}
Name PID CPU% MEM%
${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}
${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}
${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}
${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}
${top name 5} ${top pid 5} ${top cpu 5} ${top mem 5}
Disk: ${fs_used}/${fs_size} $fs_used_perc% ${color 880000}${fs_bar}${color black}
${diskiograph 40,0 000088 000088}#
${if_existing /proc/net/route enp0s31f6}
networking: enp0s31f6
Up: ${upspeed enp0s31f6}${goto 200}Down: ${downspeed enp0s31f6}
${upspeedgraph enp0s31f6 30,160 000088 000088} ${downspeedgraph enp0s31f6 30,160 000088 000088}
${else if_existing /proc/net/route wlp2s0}
networking: ${wireless_essid wlp2s0}
Up: ${upspeed wlp2s0}${goto 200}Down: ${downspeed wlp2s0}
${upspeedgraph wlp2s0 30,160 000088 000088} ${downspeedgraph wlp2s0 30,160 000088 000088}
${endif}
]];
ネットワーク・デバイスを表す enp0s31f6, wlp2s0 は使用機器によって違うので、次のコマンドなどで調べる必要が有る
ip link
~/bin/conky/clock.lua
実際にアナログ時計を描画している Lua スクリプト
初めて書いた Lua スクリプトなので、きっともっとスマートに書き直せると思う (2024/11/07 更新)
#! /usr/bin/env lua
-- conky + lua + cairo の時計
-- https://inajob.hatenablog.jp/entry/20110306/1299386373 を参考にした
require 'cairo'
require 'cairo_xlib'
function conky_string_func()
return os.date('%m/%d %H:%M')
end
cs, cr = nil
function conky_cairo_clock()
if conky_window == nil then
return
end
if cs == nil or cairo_xlib_surface_get_width(cs) ~= conky_window.width or cairo_xlib_surface_get_height(cs) ~= conky_window.height then
if cs then
cairo_surface_destroy(cs)
end
cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
end
if cr then
cairo_destroy(cr)
end
cr = cairo_create(cs)
local r = math.min(conky_window.width, conky_window.height) * 0.39 -- 全体の大きさ conky を表示する縦横幅の最低値を基準とし ×0.39 倍で使用
local origine_x = conky_window.width - r/2 -2 -- 時計の中心 x 座標 (右端から半径分+αとして2)
local origine_y = r/2 + 1 -- 時計の中心 y 座標 (左端からの半径分+αとして1 (ピッタリくっついていると見苦しく感じる))
-- 文字盤
cairo_set_source_rgba(cr, 0.93, 0.93, 0.93, 1) -- 文字盤の色指定
cairo_set_line_width(cr, 1)
cairo_arc(cr, origine_x, origine_y, r/2, 0, 2 * math.pi) -- 円描画
cairo_fill_preserve(cr) -- 文字盤塗りつぶし
cairo_set_source_rgba(cr, 0, 0, 0, 1) -- 文字盤の枠の色指定
cairo_stroke(cr)
local ts = os.date('*t')
local i,tr
cairo_set_source_rgba(cr, 0, 0, 0, 1) -- 目盛りの色指定
-- 時間、5分毎の目盛り
cairo_set_line_width(cr, 2.0) -- 1時間 (5分) 毎の目盛りの太さ
for i = 0,11 do
tr = math.pi * 2 * i / 12
cairo_move_to(cr, origine_x + 0.46*r*math.cos(tr), origine_y + 0.46*r*math.sin(tr))
cairo_line_to(cr, origine_x + r/2*math.cos(tr), origine_y + r/2*math.sin(tr))
cairo_stroke(cr)
end
-- 1分毎の目盛り
cairo_set_line_width(cr, 1.0) -- 1分毎の目盛りの太さ
for i = 0,59 do
tr = math.pi * 2 * i / 60
cairo_move_to(cr, origine_x + 0.475*r*math.cos(tr), origine_y + 0.475*r*math.sin(tr))
cairo_line_to(cr, origine_x + r/2*math.cos(tr), origine_y + r/2*math.sin(tr))
cairo_stroke(cr)
end
-- 運針
-- hour
tr = math.pi*2*(ts['hour']*60 + ts['min'])/(60*12) - math.pi/2
cairo_move_to(cr, origine_x - 0.08*r*math.cos(tr), origine_y - 0.08*r*math.sin(tr))
cairo_line_to(cr, origine_x + 0.04*r*math.cos(tr - math.pi/2), origine_y + 0.04*r*math.sin(tr - math.pi/2))
cairo_line_to(cr, origine_x + 0.35*r*math.cos(tr), origine_y + 0.35*r*math.sin(tr))
cairo_line_to(cr, origine_x + 0.03*r*math.cos(tr + math.pi/2), origine_y + 0.03*r*math.sin(tr + math.pi/2))
cairo_close_path(cr)
cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1) -- 針内部の色
cairo_fill_preserve(cr)
cairo_set_source_rgba(cr, 0, 0, 0, 1) -- 針の輪郭色
cairo_stroke(cr)
-- min
tr = math.pi*2*(ts['min']*60 + ts['sec'])/(60*60) - math.pi/2
cairo_move_to(cr, origine_x - 0.08*r*math.cos(tr), origine_y - 0.08*r*math.sin(tr))
cairo_line_to(cr, origine_x + 0.04*r*math.cos(tr - math.pi/2), origine_y + 0.04*r*math.sin(tr - math.pi/2))
cairo_line_to(cr, origine_x + 0.44*r*math.cos(tr), origine_y + 0.44*r*math.sin(tr))
cairo_line_to(cr, origine_x + 0.04*r*math.cos(tr + math.pi/2), origine_y + 0.04*r*math.sin(tr + math.pi/2))
cairo_close_path(cr)
cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1)
cairo_fill_preserve(cr)
cairo_set_source_rgba(cr, 0, 0, 0, 1)
cairo_stroke(cr)
-- sec
cairo_set_source_rgba(cr, 1, 0, 0, 1) -- 秒針の色指定
cairo_move_to(cr, origine_x - 0.15*r*math.cos(math.pi*2*ts['sec']/60 - math.pi/2), origine_y - 0.15*r*math.sin(math.pi*2*ts['sec']/60 - math.pi/2))
cairo_line_to(cr, origine_x + 0.425*r*math.cos(math.pi*2*ts['sec']/60 - math.pi/2), origine_y + 0.425*r*math.sin(math.pi*2*ts['sec']/60 - math.pi/2))
cairo_stroke(cr)
cairo_set_source_rgba(cr, 1, 0, 0, 1) -- 中心円の色指定
cairo_set_line_width(cr, 1)
cairo_arc(cr, origine_x, origine_y, 0.018*r, 0, 2 * math.pi)
cairo_fill(cr)
cairo_destroy(cr)
cr = nil
end
~/bin/conky/weather.py
(2022/09/06 更新)
天気予報を取得するスクリプト
https://tenki.jp/forecast/3/16/4410/13204/10days.html の部分は一度 日本気象協会 tenki.jp/ へ実際にアクセスして自分の居住地に合わせる必要がある
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fileencoding=utf-8 fileformat=unix
import requests
import re
from bs4 import BeautifulSoup
html = requests.get('https://tenki.jp/forecast/3/16/4410/13204/10days.html')
soup = BeautifulSoup(html.content, "html.parser")
# print(soup) # 全体
for s in soup.find_all('dd', class_='forecast10days-actab')[:3]: # 最初の3日分
print(re.sub(r'(?<=\d)月', '/', re.sub(r'(?<=\d)日', '', s.find_all('div', class_='days')[0].text)) +
s.find_all('div', class_='forecast')[0].text + ' ' +
s.find_all('div', class_='temp')[0].text.replace('℃', '/', 1).replace('℃', '°C ') +
s.find_all('div', class_='prob-precip')[0].text)
~/bin/conky/earthquake.sh
(2022/09/06 更新)
地震情報を取得するスクリプト
#!/bin/sh
case "$(uname)" in
Darwin|*BSD) sed="sed -E";;
*) sed="sed -r";;
esac
w3m -T text/html -M -s -dump -cols 100000 -o pseudo_inlines=false https://earthquake.tenki.jp/bousai/earthquake/ |
grep -E "^ +[0-9]+年[0-9]+月[0-9]+日 [0-9]+時[0-9]+分頃 +[^ ]+ +M[0-9.]+ +[0-9][強弱]?" |
head --lines=3 |
$sed "s/^ +[0-9]+年[0-9]+月([0-9]+日) ([0-9]+)時([0-9]+)分頃 +([^ ]+) +(M[0-9.]+) +([0-9][強弱]?)/\\1\\2:\\3\\5震度\\6\\4/g"
exit 0
~/bin/conky/ncal3.sh
- 月を跨いでも前後の週の同じ曜日を解りやすくするために ncal コマンドと似た形式で出力したい
- しかし ncal コマンドの出力はパイプ経由すると当日の強調表示情報が消える
- 出力の横幅を少なくするために、月を跨る空白要素は詰めたい
といった理由でシェル・スクリプトを使っている
#!/bin/sh
case "$(uname)" in
Darwin|*BSD) sed="sed -E";;
*) sed="sed -r";;
esac
transpose(){ # 行・列を入れ替える (出力はタブ区切り)
grep -vE "^ +$" | # スペースのみの行は除外
$sed 's/ / @ /g' | # 空白要素をダミーに置き換え
nawk '{ # 実際の入れ替えルーチン
for (i=1; i<=NF; i++) {
a[NR,i] = $i
}
}
NF>p {
p = NF
}
END {
for(j=1; j<=p; j++) {
str=a[1,j];
for(i=2; i<=NR; i++){
str=str"\t"a[i,j];
}
print str
}
}' |
$sed 's/@//g' # ダミー削除
}
calendar=$( LC_ALL=ja_JP.utf8 cal -3 ) # 日本語ロケールで前後3ヶ月取得
if cat <<-_EOF_ |
$calendar
_EOF_
# 出力が「何月何年」で始まる形式と先頭行に年が表示され、次の行に月だけ表示の形式が有る
grep -Eq "^\\s*[0-9]{4}$" ; then # 西暦だけの行が有るか? 有れば calendar データは 2 行目以降を使う
calendar=$( cat <<-_EOF_ |
$calendar
_EOF_
tail --line=+2 )
fi
# 1行目の 何月 何年取得
month=$( cat <<- _EOF_ |
$calendar
_EOF_
head --line=1
)
# 曜日のみ+一週間分のみ
week=$( cat <<- _EOF_ |
$calendar
_EOF_
head --line=2 |
tail --line=1 |
cut -b1-27
)
# 実際のカレンダー・日付部分
calendar=$( cat <<- _EOF_ |
$calendar
_EOF_
$sed -e 's/ _\x8([0-9])_\x8([0-9]) /<\1\2>/g' \
-e 's/ _\x8 _\x8([0-9]) / <\1>/g' |
tail --line=+3
)
# 先月カレンダー
last_month=$( cat <<- _EOF_ |
$calendar
_EOF_
cut -c1-21
)
# 今月カレンダー
this_month=$( cat <<- _EOF_ |
$calendar
_EOF_
cut -c22-43 |
$sed 's/(<[0-9]+>)/ \1 /g'
)
# 来月カレンダー
next_month=$( cat <<- _EOF_ |
$calendar
_EOF_
cut -c44-65
)
cat << _EOF_ |
$month
_EOF_
cut -b2-20,30-40,50-64 |
sed -E -e 's/([0-9]+) *([0-9]+月)/\1 \2/g'
cat << _EOF_ |
$week
$last_month
$this_month
$next_month
_EOF_
transpose |
$sed -e 's/([日月火水木金土])\t\t/\1 /g' \
-e 's/([日月火水木金土])\t/\1 /g' \
-e 's/\t\t/\t/g' \
-e 's/\t$//g' \
-e 's/\t(<[0-9][0-9])/\1/g' \
-e 's/\t([<0-9][0-9])/ \1/g' \
-e 's/\t/ /g' \
-e 's/> />/g' \
exit 0