paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

PayPayの支払いデータを自分で集計したい3

今回は前回の集計をグラフ化してみます。
②の部分ですね。

  1. ツール単体で集計
  2. 集計結果を可視化
  3. スマホアプリ用にビルド

追記分はこちら。
matplotlibに読ませる様のリストを作成してます。

sqlで出したものをまたリストにいれるというマヌケな処理になってしまいました。
綺麗に出来る方法はあるものか...

diff --git a/app.py b/app.py
index 45d6cf1..04bfc50 100644
--- a/app.py
+++ b/app.py
@@ -40,48 +40,13 @@ def main():
                  count("利用店名・商品名") FROM pay GROUP BY "利用日/キャンセル日", \
                  "利用店名・商品名" ORDER BY "利用日/キャンセル日"')
 
-    datelist = list()
     for x in cur.fetchall():
         print(*x)
-        datelist.append(x[0])
-
-    datelist = list(set(datelist))
-    datelist.sort()
 
     cur.execute('SELECT sum("支払総額") FROM pay')
     # Use 'format' for use astarisk
     print('Total: {}'.format(*cur.fetchone()))
 
-    # Top 3 stores that paid most
-    cur.execute('SELECT "利用店名・商品名", count("利用店名・商品名") FROM pay GROUP BY "利用店名・商品名" ORDER BY count("利用店名・商品名") DESC')
-
-    top3 = list()
-    for x in cur.fetchall()[:3]:
-        top3.append(x[0])
-
-    no1_list = list()
-    no2_list = list()
-    no3_list = list()
-
-    for i,x in enumerate(top3):
-        cur.execute('SELECT "利用日/キャンセル日", ?, sum(CASE WHEN "利用店名・商品名" = ? THEN "支払総額" ELSE 0 END) FROM pay \
-                    GROUP BY "利用日/キャンセル日", ? ORDER BY "利用日/キャンセル日"', [x,x,x])
-
-        # Create paymant list
-        for y in cur.fetchall():
-            if i == 0:
-                no1_list.append(y[2])
-            elif i == 1:
-                no2_list.append(y[2])
-            else:
-                no3_list.append(y[2])
-
-    i = 0
-    for t in [no1_list, no2_list, no3_list]:
-        if len(t) != 0:
-            print(datelist, t, f'label={top3[i]}')
-            i += 1
-
     con.close()
 
 if __name__ == '__main__':

支払い合計のTOP3を出してグラフ用のリストに渡す様にしました。

動かすと以下の出力になります。

❯ python app.py ../ドキュメント/paypay/detail202311\(5569\).csv
2023-09-30 ヤフージャパン 508 1
2023-10-04 PayPay 町かど酒場XXXX 3200 6
2023-10-06 PayPay XXXX Dining 1900 1
2023-10-07 PayPay 町かど酒場XXXX 2150 4
2023-10-08 PayPay 町かど酒場XXXX 2700 6
2023-10-09 PayPay 町かど酒場XXXX 1900 4
2023-10-12 PayPay 町かど酒場XXXX 2300 5
2023-10-13 PayPay 町かど酒場XXXX 1150 2
2023-10-14 PayPay 町かど酒場XXXX 3700 8
2023-10-14 PayPay XXXX Dining 2000 1
2023-10-15 PayPay 町かど酒場XXXX 4000 8
2023-10-16 PayPay 町かど酒場XXXX 1450 2
2023-10-18 PayPay 町かど酒場XXXX 950 2
2023-10-20 PayPay 町かど酒場XXXX 2200 4
2023-10-21 PayPay 町かど酒場XXXX 3500 6
2023-10-22 PayPay 町かど酒場XXXX 3900 7
2023-10-26 PayPay 町かど酒場XXXX 3950 8
2023-10-27 PayPay 町かど酒場XXXX 950 2
2023-10-28 PayPay 町かど酒場XXXX 2700 5
2023-10-29 PayPay ハリケーン 3020 1
2023-10-29 PayPay 町かど酒場XXXX 500 1
Total: 48628
['2023-09-30', '2023-10-04', '2023-10-06', '2023-10-07', '2023-10-08', '2023-10-09', '2023-10-12', '2023-10-13', '2023-10-14', '2023-10-15', '2023-10-16', '2023-10-18', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-26', '2023-10-27', '2023-10-28', '2023-10-29'] [0, 3200, 0, 2150, 2700, 1900, 2300, 1150, 3700, 4000, 1450, 950, 2200, 3500, 3900, 3950, 950, 2700, 500] label=PayPay 町かど酒場XXXX
['2023-09-30', '2023-10-04', '2023-10-06', '2023-10-07', '2023-10-08', '2023-10-09', '2023-10-12', '2023-10-13', '2023-10-14', '2023-10-15', '2023-10-16', '2023-10-18', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-26', '2023-10-27', '2023-10-28', '2023-10-29'] [0, 0, 1900, 0, 0, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] label=PayPay XXXX Dining
['2023-09-30', '2023-10-04', '2023-10-06', '2023-10-07', '2023-10-08', '2023-10-09', '2023-10-12', '2023-10-13', '2023-10-14', '2023-10-15', '2023-10-16', '2023-10-18', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-26', '2023-10-27', '2023-10-28', '2023-10-29'] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3020] label=PayPay ハリケーン

下三行が追加したコードで、日付リスト・各日毎の支払金額が合計金額の多い店舗順に出てきます。
このフォーマットをmatplotlibに読ませればグラフ化できます。

jupyterlab

グラフや画面系の確認はjupyterlabがいい感じに検証できるのでこちらを使います。
いきなりですが先程の出力結果をちょっと修正してmatplotlibに読ませるとこうなります。

明細の都合上日本語化モジュールいれたのとフォントサイズいじってます。

import matplotlib.pyplot as plt
import japanize_matplotlib

datelist = ['2023-09-30', '2023-10-04', '2023-10-06', '2023-10-07', '2023-10-08', '2023-10-09', '2023-10-12', '2023-10-13', '2023-10-14', '2023-10-15', '2023-10-16', '2023-10-18', '2023-10-20', '2023-10-21', '2023-10-22', '2023-10-26', '2023-10-27', '2023-10-28', '2023-10-29']

top = [0, 3200, 0, 2150, 2700, 1900, 2300, 1150, 3700, 4000, 1450, 950, 2200, 3500, 3900, 3950, 950, 2700, 500] 
two = [0, 0, 1900, 0, 0, 0, 0, 0, 2000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
thi = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3020] 

plt.bar(datelist, top, label='町かど酒場XXXX')
plt.bar(datelist, two, label='XXXX Dining')
plt.bar(datelist, thi, label='ハリケーン')

plt.title('今月のPayPay支払い')
plt.ylabel('円(¥)')
plt.xticks(rotation=45)
plt.legend(loc='upper left', ncols=3, fontsize=8)
plt.tick_params(labelsize=7)
plt.ylim(0, max(top) * 1.5)
plt.show()

OK。いい感じにグラフできました。
店舗ごとの並列棒グラフにするつもりでしたが合計と割合が分かるしこの積み上げ棒グラフままでもいいか。

今後

月ごとのテーブル、グラフ出力と基本的な処理は出来たので一旦こんなものでいいでしょう。
コードはもう少し成形しますがこれからKivyに連携させるという結構大変な作業が待ってます。

PayPayの支払いデータを自分で集計したい2

前回PayPayの日毎の集計をSQLで出力させました。
最終目標はスマホアプリとして操作させるということで

  1. ツール単体で集計
  2. 集計結果を可視化
  3. スマホアプリ用にビルド

の1-2としてpythonでの出力をやります。

コード

早速ですが全体。
CSVを引数で読んでsqliteに格納してからsql文で出力します。
dbファイルが作成されるのもなんだかなということでいったんインメモリで動かすようにしました。

sql分を直で書くのはよろしくないかもしれませんが前回の文を流用したのでさくっとできました。
変数埋め込みの書き方が都合上バラけてしまったのが悔しいです。

import sys
import sqlite3
import datetime


def subDateisoformat(d):
    df = datetime.datetime.strptime(d, '%Y/%m/%d')
    sub_y, sub_m, sub_d = df.year, df.month, df.day

    return datetime.date(sub_y, sub_m, sub_d).isoformat()


def main():
    # Delete BOM in file
    with open(sys.argv[1], 'r', encoding='utf-8-sig') as f:
        csvfile = f.readlines()

    con = sqlite3.connect(':memory:')
    cur = con.cursor()

    for n, c in enumerate(csvfile):
        field = c.split(',')
        if n == 0:
            headers = (field[0], field[1], field[6])
            # Create sql statement becouse can't used qmark style
            headers = f'CREATE TABLE pay ({field[0]} TEXT,{field[1]} TEXT, \
                       {field[6]} TEXT)'
            cur.execute(headers)
        else:
            # Delete double quotes
            field[0] = field[0].replace("\"","")
            field[1] = field[1].replace("\"","")
            field[6] = field[6].replace("\"","")

            field[0] = subDateisoformat(field[0])
            insert_row = (field[0], field[1], field[6])
            cur.execute('INSERT INTO pay VALUES (?,?,?)', insert_row)

    cur.execute('SELECT "利用日/キャンセル日", "利用店名・商品名", sum("支払総額"), \
                 count("利用店名・商品名") FROM pay GROUP BY "利用日/キャンセル日", \
                 "利用店名・商品名" ORDER BY "利用日/キャンセル日"')

    for x in cur.fetchall():
        print(*x)

    cur.execute('SELECT sum("支払総額") FROM pay')
    # Use 'format' for use astarisk
    print('Total: {}'.format(*cur.fetchone()))

    con.close()

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print('Be specify csvfile.')
        sys.exit(1)

    main()

解説

難しいことはやっていないので2つだけ。

BOM付きファイル読み込み

PayPayの利用明細はBOM付きでした。
エンコードを指定して解決。

  • 指定なし
>>> with open('detail202311(5569).csv', 'r') as f:
...     csvfile = f.readlines()
... 
>>> csvfile[0]
'\ufeff"利用日/キャンセル日","利用店名・商品名","利用者","支払区分","利用金額","手数料","支払総額","当月支払金額","翌月以降繰越金額","調整額","当月お支払日"\n'
>>> with open('detail202311(5569).csv', 'r', encoding='utf-8-sig') as f:
...     csvfile = f.readlines()
... 
>>> csvfile[0]
'"利用日/キャンセル日","利用店名・商品名","利用者","支払区分","利用金額","手数料","支払総額","当月支払金額","翌月以降繰越金額","調整額","当月お支払日"\n'
日付の修正

明細はyyyy/mm/ddで出るのでISOフォーマットに直します。
1桁日付も0埋めしました。

>>> subDateisoformat('2023/12/1')
'2023-12-01'
>>> subDateisoformat('2023/12/11')
'2023-12-11'

動かしてみる

先月分出してみます。

❯ python3 --version
Python 3.10.12
❯ python3 paycalc.py detail202311\(5569\).csv
2023-09-30 ヤフージャパン 508 1
2023-10-04 PayPay 町かど酒場XXXX 3200 6
2023-10-06 PayPay XXXX Dining 1900 1
2023-10-07 PayPay 町かど酒場XXXX 2150 4
2023-10-08 PayPay 町かど酒場XXXX 2700 6
2023-10-09 PayPay 町かど酒場XXXX 1900 4
2023-10-12 PayPay 町かど酒場XXXX 2300 5
2023-10-13 PayPay 町かど酒場XXXX 1150 2
2023-10-14 PayPay 町かど酒場XXXX 3700 8
2023-10-14 PayPay XXXX Dining 2000 1
2023-10-15 PayPay 町かど酒場XXXX 4000 8
2023-10-16 PayPay 町かど酒場XXXX 1450 2
2023-10-18 PayPay 町かど酒場XXXX 950 2
2023-10-20 PayPay 町かど酒場XXXX 2200 4
2023-10-21 PayPay 町かど酒場XXXX 3500 6
2023-10-22 PayPay 町かど酒場XXXX 3900 7
2023-10-26 PayPay 町かど酒場XXXX 3950 8
2023-10-27 PayPay 町かど酒場XXXX 950 2
2023-10-28 PayPay 町かど酒場XXXX 2700 5
2023-10-29 PayPay ハリケーン 3020 1
2023-10-29 PayPay 町かど酒場XXXX 500 1
Total: 48628

同じく店名マスクしました。
出力もsqliteと同じで日付修正したのでソートも効いているしOKですね。

合計も出すようにしたのですがほぼ飲み屋で5万弱...ちょっと飲みすぎたね。

ちなみに7月の支払時。

❯ python3 paycalc.py detail202307\(5569\).csv
2023-05-31 ヤフージャパン 508 1
2023-06-03 PayPay 町かど酒場XXXX 2200 4
2023-06-03 PayPay XXXX Dining 1800 1
2023-06-09 PayPay 町かど酒場XXXX 900 2
2023-06-10 PayPay XX商店 755 1
2023-06-10 PayPay 町かど酒場XXXX 700 1
2023-06-11 PayPay 町かど酒場XXXX 1000 2
2023-06-18 PayPay 町かど酒場XXXX 2700 5
2023-06-19 PayPay 町かど酒場XXXX 2750 5
2023-06-25 PayPay XXXX Dining 2100 1
2023-06-30 PayPay 町かど酒場XXXX 1350 3
Total: 16763

少ないですね。使う金額はそんなに変わらないですが通いのペースが上がってしまったのがわかりますw
XXXX Diningというのも同じ街にあってたまに行くバーなので一応マスクしてますw

あとはこのコードをKivyに埋め込んで完成です。
が、見た目も少し良くしたいので一回グラフ化もさせます。

PayPayの支払いデータを自分で集計したい1

今年はコロナも落ち着きそうと言うことで引きこもりを脱却すべく外に飲みに行くようになりました。
地元に気軽に行けるちょっとお洒落な立ち飲み屋があり今年は平均週一回以上通ってます。

立ち飲みという形態上キャッシュオンなのですが毎回現金を用意するのが面倒だったので4月にpaypayを導入しました。
今年前半こそ週一ペースだったのですが通っていくうちに知り合いも増えたということもあり、だんだん頻度が上がってしまい今月・先月の請求がビックリするほど増加していました。

生活に困るレベルではないですが出費はなるべく押さえたいところです。
というわけで内訳を出してウォッチしようと思います。

paypayアプリから請求金額や使った店舗の集計は出来ますが、キャッシュオンで都度支払ってかつ同じ店に通っている身としては1日何件決済したかどうかのペースが知りたいところです。

CSV読んでグラフ化して完了!としたいところですがpaypayの気に入らないところで利用明細のダウンロードがアプリからしか出来ません。

スマホでダウンロードしてPCに移してCSVから起こして...って毎月やる?

こんな運用するならスマホから見れるようにしようということでいっちょ集計アプリを作ろうと思います。 

ロードマップ

いきなりアプリを作ろうとすると完成まで時間がかかるので段階を踏みます。

  1. ツール単体で集計
  2. 集計結果を可視化
  3. スマホアプリ用にビルド

というわけでまずは①です。 

集計ツール

月の支払い合計を出すだけなら何を使ってもできるのですが、使いすぎを見つけるため1日毎にどの店でいくら決済したかというのを集計したいです。

pythoncsvモジュールでなんとかできないかと思いましたがすぐにはできなかったのでpandasかSQLあたりを使います。

いずれスマホで触るアプリにしようと考えるとパッケージをボンボン入れてあまりサイズを大きくしたくないのでSQLで考えます。

なのでpythonsqliteのセットくらいになりますね。 

sqliteで集計

まずはsqliteでサクッと集計してみましょう。
csvインポート機能もあります。

とりあえず先月分。 

バージョン
❯ sqlite3 --version

3.37.2 2022-01-06 13:25:41 872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5dalt1
csvインポート

型が指定できないのは困りますがインポート機能便利です。

sqlite> .mode csv
sqlite> .import 'detail202311(5569).csv' pay
スキーマ

CSVのヘッダです。  
必要なのは利用日、利用店、支払い総額くらいですかね。

sqlite> .schema
CREATE TABLE IF NOT EXISTS "pay"(
  "利用日/キャンセル日" TEXT,
  "利用店名・商品名" TEXT,
  "利用者" TEXT,
  "支払区分" TEXT,
  "利用金額" TEXT,
  "手数料" TEXT,
  "支払総額" TEXT,
  "当月支払金額" TEXT,
  "翌月以降繰越金額" TEXT,
  "調整額" TEXT,
  "当月お支払日" TEXT
);
1日毎かつ店毎の集計

CSV形式で出力します。  

見にくいですがテーブル形式だとスマホからもっと見にくいですからね。
処理上仕方無いのかも知れませんがデフォルトで全角なの腹立ちますね(笑)
日本の利用明細は何故か全部こうだ。

sqlite> .header on
sqlite> select "利 用 日 /キ ャ ン セ ル 日 ", "利 用 店 名 ・ 商 品 名 ",sum("支 払 総 額 "), count("利 用 店 名 ・ 商 品 名 ") from pay group by "利 用 店 名 ・ 商 品 名 ", "利 用 日 /キ ャ ン セ ル 日 " order by "利 用 日 /キャ ン セ ル 日 " ASC;
"利 用 日 /キ ャ ン セ ル 日 ","利 用 店 名 ・ 商 品 名 ","sum(""支 払 総 額 "")","count(""利 用 店 名 ・ 商 品 名 "")"
2023/10/12,"P a y P a y   町 か ど 酒 場 XXXX ",2300,5
2023/10/13,"P a y P a y   町 か ど 酒 場 XXXX ",1150,2
2023/10/14,"P a y P a y   町 か ど 酒 場 XXXX ",3700,8
2023/10/14,"P a y P a y   XXXX   D i n i n g ",2000,1
2023/10/15,"P a y P a y   町 か ど 酒 場 XXXX ",4000,8
2023/10/16,"P a y P a y   町 か ど 酒 場 XXXX ",1450,2
2023/10/18,"P a y P a y   町 か ど 酒 場 XXXX ",950,2
2023/10/20,"P a y P a y   町 か ど 酒 場 XXXX ",2200,4
2023/10/21,"P a y P a y   町 か ど 酒 場 XXXX ",3500,6
2023/10/22,"P a y P a y   町 か ど 酒 場 XXXX ",3900,7
2023/10/26,"P a y P a y   町 か ど 酒 場 XXXX ",3950,8
2023/10/27,"P a y P a y   町 か ど 酒 場 XXXX ",950,2
2023/10/28,"P a y P a y   町 か ど 酒 場 XXXX ",2700,5
2023/10/29,"P a y P a y   ハ リ ケ ー ン ",3020,1
2023/10/29,"P a y P a y   町 か ど 酒 場 XXXX ",500,1
2023/10/4,"P a y P a y   町 か ど 酒 場 XXXX ",3200,6
2023/10/6,"P a y P a y   XXXX   D i n i n g ",1900,1
2023/10/7,"P a y P a y   町 か ど 酒 場 XXXX ",2150,4
2023/10/8,"P a y P a y   町 か ど 酒 場 XXXX ",2700,6
2023/10/9,"P a y P a y   町 か ど 酒 場 XXXX ",1900,4
2023/9/30,"ヤ フ ー ジ ャ パ ン ",508,1

店名は一応マスクしてます。
他の飲み屋の決済もありますが先月の集計です。

町かど酒場が例の立ち飲み屋です。 
うーん、なかなか通ってますねw

長居して4000円周辺の回が何回かありますね。
これが良くなかったんだな。
フードも入ってるけど1件で7-8回注文してるのでこれも減らさねば。

記事執筆前にpythonでどうにかしようとウンウン唸っていたのですがSQLで一発でした。
SQL文は優秀ですねえ。


日付でソートしたかったのですが上手く並んでいませんね。
日付がTEXT型しかないのは知っていますがISOフォーマットじゃないと日付と認識しないようでこれでは型の変換もできないのでどこかで変換を噛まさないといけませんね。

とりあえず目的の出力は果たせました。
今回はここまでで次回pythonから呼んでみたいと思います。

自宅のグローバルIP変化をslackで通知する

外から家の環境にアクセスする時はSSL VPNを張るのですがある時繋げなくなってしまいました。
思い当たるのはVPN装置のpfsenseが落ちているかグローバルIPが変わるしか心当たりがありません。

帰宅後グローバルIPが変わっていたことが判明したのですが、変わるなんて滅多に無かったのでタイミングがわかりません。

ISPの簡易レンタルルータなのでログみても良くわかりませんでした。
再起動したかキャリア側の期間終了でDHCP再取得したような感じですが... WAN側が同軸ケーブルのルータなので置き換えができないんですよね。

でも急に繋げなくなると困るので監視ツールを作ります。

グローバルIP監視

ルータにログインしてスクレイピングして、とか考えましたがグローバルIP診断サイトにwgetとかでできるじゃんと思いつきました。
診断サイトにcurlでアクセスしてIPを正規表現で抜けばOK。
記事用にマスクします。

❯ curl -s http://www.myglobalip.com/ | grep -oP "(\d{1,3}\.){3}\d{1,3}" | sed -r 's/[0-9]{1,3}/xxx/g'
xxx.xxx.xxx.xxx

これを一次ファイルに書いておいて定期的に上記のシェルを実行したタイミングで突合すればOKですね。

通知ツール

出先でも分かるようにスマホに飛ばしたいです。

上記と同じくshellから飛ばして終わらせたい。
と調べたら

らへんがお手軽に出来そうです。

shellからのmail送信試したのですがgmailは自前MTAとかだとセキュリティを下げないと受信できないらしく、このためにセキュリティ下げるのはなあと思い諦めました。

www.digitalocean.com

後者のchat系は沢山ありますがたまたまスマホにslackが入っていたのでこちらに通知するようにします。

APIの準備

APIのページに行ったらフレームワークやWebソケットがどうのと種類がたくさんあってどれを使えばいいかパッとわかりません。

curlからメッセージを飛ばすチュートリアルがあったのでこちらを参考にします。

Posting messages using curl | Slack

APIはCreate appから連携するworkspaceと権限等設定して完了です。
(この辺の設定は通勤中にスマホからポチポチとやったのでスクショがありません)

Slackにインストール

これも忘れてしまいましたが作成過程のポップアップ等でSlack側にAPIをインストールできたと思います。 調べれば出るので割愛。

APIのテスト

Authenticationのテストをします。 (tokenはマスク)

❯ curl -d "token=xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://slack.com/api/auth.test
{"ok":true,"url":"https:\/\/masashi-qmv6034.slack.com\/","team":"masashi","user":"the_workspace_reporte", () }%    

OKが返ったので成功した様です。

テストメッセージを飛ばします。

 ❯ curl -d "text=Hi I am a bot that can post messages to any public channel." -d "channel=home-lab" -H "Authorization: Bearer xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -X POST https://slack.com/api/chat.postMessage
{"ok":true,"channel":"(略)","ts":"(略)","message":{"bot_id":"B06491FEEAV","type":"message","text":"Hi I am a bot that can post messages to any public channel.","user":"(略)}}}%    

slack側を見るとメッセージ受信しました。OKです。
通知ツールの名前がよくわからないデフォルトのやつになってしまった。
どう変更するんだろ。まあこのままでもいいか。

IPアドレス変更メッセージを送信

IPが変わった体でメッセージを飛ばしてみます。

マスク版IPを変数に入れておいて、

IPADDRESS=$(curl -s http://www.myglobalip.com/ | grep -oP "(\d{1,3}\.){3}\d{1,3}" | sed -r 's/[0-9]{1,3}/xxx/g')
❯ curl -d "text=IPアドレスが変更されました。$IPADDRESS" -d "channel=home-lab" -H "Authorization: Bearer $(cat slacktoken)" -X POST https://slack.com/api/chat.postMessage
{"ok":true,"channel":"(略)","ts":"(略)","message":{"bot_id":"B06491FEEAV","type":"message","text":"IP\u30a2\u30c9\u30ec\u30b9\u304c\u5909\u66f4\u3055\u308c\u307e\u3057\u305f\u3002<http:\/\/xxx.xxx.xxx.xxx|xxx.xxx.xxx.xxx>","user":()}}}%   

これも送信OK。

slackでも無事に受信しました。
ちなみにメッセージ内の改行が効かなかったので2回実行してます。

旧IP、新IPの診断もOKです。
globalipaddressファイルに今のIPを書いてます。

test $(echo $IPADDRESS) = $(cat globalipaddress) ; echo $?
0

あとはこれらをスクリプト化してcronに仕込んでおけばOKですね。

まとめ

slack apiの豊富さに驚いて他のツール通知(LINE, Facebook, X等)にすればよかったかなと思いましたが意外と簡単に作れました。
とりあえずグローバルIPなんて能動的に見るものではないので、push通知があるツールで作りたかったのですがなんとかなりそうです。
home-lab用のチャンネルなので他にも家のラボ系の通知にも使えそう。

とりあえずこれでいつIPが変わってもVPNを貼り直すことができます。
まあ、IPの接続先変更はOKとしてもOPENVPN側のconfigを直す必要があるのですが...

linuxのriceターミナルに出てくるアレのパッケージ名

あらまし

今年の前半にunixporn、riceの概念を知って興味を持ち色々調べたのですが、記事や動画を見ていく中でどうしてもわからないものがありました。

それがこのターミナルのアスキーアートです。 サイト内のパックマンのやつね。

terminalroot.com

他にもインベーダーとかいろいろな絵が表示されて、riceの動画なんかだとターミナル起動時に出力されてかっこいいんですよね。

私もインストールしたいと思い「terminal ascii art pacman」とかいろいろなワードで検索したのですがヒット無し。
諦めてしばらく経ち、2代目ubuntuも少しいい感じにしてきたところで(シーズンだし)最近この記事を見つけました。

itsfoss.com

内容はタイトルの通りですが中に探していたパッケージが!

Shell Color Scripts

gitlab.com

Shell Color Scriptsというパッケージ名らしいです。
早速インストールしよう。 ドキュメントに沿ってubuntuはsourceからビルドします。

❯ git clone https://gitlab.com/dwt1/shell-color-scripts.git
❯ cd shell-color-scripts
❯ sudo make install
❯ sudo cp completions/_colorscript /usr/share/zsh/site-functions

実行

実行してみます。(pywal外してます)

これだー! OK!

結構パターン入ってます。
ゼルダのやつかっこいいですね。

あとはターミナル起動時にコマンド実行するようにしてターミナルrice一旦完成です。
ターミナル起動が楽しみだぜ。

2代目UbuntuのGNOMEでrice

ここ最近記事に登場しているNUCのubuntuですがカッコいいデスクトップはテンションが上がるのでこの子もrice化します。
この子はハングアップせず安定しているのでGNOMEのままやろうと思います。

conky

ずっと使ってるリソースモニタツール。
バックアップからconkyrcをコピーして終了。
居住地方の天気情報も取って表示してます。
これも色文字表示とか入れたいのだがなかなか...

zsh

お洒落ターミナルはzsh + oh-my-zsh + powerlevel10kで決まり!
これは何故か設定ファイルをコピーせずに再設定してしまいました。

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" 
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k
cp dotfiles/.zshrc .
zsh
p10k configure  

ubuntuはライブラリ系のエラーが出るので追加。

/usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0' from LD_PRELOAD cannot be preloaded
sudo apt install gtk3-nocsd

wallpaper

先代と同じサムスピの骸流島です。
SNKのドット本当好き。

日本語でもいいですが「gairyu isle」で検索するとたくさん出てきます。

GNOME Extention

www.youtube.com

youtubeのカスタム動画をみて良さそうなのを選択。
あとはトップバーを半透明にしたい。

有効化しているのはこの辺。

  • Aylur's Widget
    • work spaceの○表示が可愛かったので採用
    • 他の機能はあまり使いこなせていません
  • Caffeine
  • Pop Shell
    • 後述

pop shell

タイルウィンドウにしたかったので導入。
自動サイジング楽で慣れると結構快適です。

先代はインストール失敗して使えなかったのですが何でだろ?
同じバージョンでもアップデートからだとどこかの構成が違うんだろうか。

まあ使えたのでOKです。 タイリングの画像は撮ってませんでした。

というわけで一旦こんな感じです。

今までのデスクトップデザインを踏襲しつついい感じです。
ちなみにサブ機ということで昔の余りディスプレイ使っているので画角は4:3ですw

pywal

背景と同じカラースキームにするツール。

❯ pip3 install pywal

-iで背景のカラースキームを読み込みます。

❯ wal -i ダウンロード/Samsho5sp_bg_gairyu_isle_2.webp
[I] image: Using image bg_gairyu2.jpg.
[I] colors: Generating a colorscheme.
[I] colors: Using wal backend.
[E] wal: Imagemagick wasn't found on your system.
[E] wal: Try another backend. (wal --backend)

パッケージ不足のエラーが出たのでisuueを見つつ以下を追加。

❯ pip3 install --user colorz
❯ sudo apt install imagemagick

再度実行。

これが...

こうなります。
本当はターミナル半透明なんだけどスクショだと地味な感じになってしまいました。

色が変わって雰囲気も変わりました。
色味が合うのはいいけど青系が見にくいな...

変更されるのは現在のターミナルだけっぽいのでzshrcに書かなくては。

まとめ

参考にした動画には遠く及びませんが使っていて楽しい環境にはなってきました。
動かしているところまで取っていないので一枚絵だと微妙かもしれませんが、いい感じになったところでここまでにします。
GTKテーマも変更したい。

いいExtentionとか入れたらまた書きます。

おまけ

  • riceについて

UnixPornをお洒落に楽しむ - おしゃれな気分でプログラミング

KDE環境をrice化する - paloma blog

Home labにGiteaをデプロイする

前回ラボのステージング環境を作りました。
本題のGit管理ツールのデプロイもOKだったので本番のラボにデプロイします。

gitea

オープンソースのGit管理ツールはGitlabくらいしか知らなかったのですが結構リソース要求が高い様です。
色々調べるとGiteaという軽量なツールがあるそうなのでこちらを採用することにしました。

about.gitea.com

composeファイル

Docker installはrootlessとrootあり版がありますが、とりあえずはroot使う用事がないのでrootless版にします。
公式のcomposeファイルで特にカスタムなしでデプロイします。

composeファイルのバージョンが2だとラボに対応していなかったので他のファイルを合わせて3.3に修正しました。

volumeのデータ置き場を統一するべきなのですがあまり設計していないのでとりあえずデフォルトです。

version: "3.3"

services:
  server:
    image: gitea/gitea:1.20.5-rootless
    restart: always
    volumes:
      - ./data:/var/lib/gitea
      - ./config:/etc/gitea
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:2222"

ステージング環境からファイルを持ってきます。
multipass mountではディレクトリの中身が表示されないという事象に陥ったので一旦transferで持ってきました。

❯ multipass transfer dev-lab:/home/ubuntu/gitea/docker-compose.yml .
❯ ls docker-compose.yml
docker-compose.yml
❯ scp docker-compose.yml masashi@10.0.1.1:/home/masashi/gitea
docker-compose.yml    

デプロイ

ラボ側にディレクトリ準備します。(上のscp時に作成済み)

masashi@lab-docker1:~$ mkdir gitea
masashi@lab-docker1:~$ cd gitea/
masashi@lab-docker1:~/gitea$ mkdir {data,config}
masashi@lab-docker1:~/gitea$ ls
config  data

ステージングにもラボにもdocker-composeコマンドを入れていないのでswarmのserviceコマンドでデプロイ。
restartのエラーは一旦無視します。

masashi@lab-docker1:~/gitea$ docker stack deploy -c docker-compose.yml gitea
Ignoring unsupported options: restart

Creating network gitea_default
Creating service gitea_server

コンテナ起動しましたよ。

masashi@lab-docker1:~/gitea$ docker service ls
ID             NAME                  MODE         REPLICAS   IMAGE                           PORTS
29w5a2b2snfy   dokuwiki_dokuwiki     replicated   1/1        bitnami/dokuwiki:20230404       *:82->8080/tcp
plup1b33qmjy   firefly_app           replicated   1/1        fireflyiii/core:latest          *:80->8080/tcp
u0009w7ryo30   firefly_db            replicated   1/1        mariadb:latest                  
xj6n7hbbhowc   gitea_server          replicated   1/1        gitea/gitea:1.20.5-rootless     *:2222->2222/tcp, *:3000->3000/tcp
luna6ms9v7bi   pi-hole_pihole        replicated   1/1        pihole/pihole:latest            *:53->53/tcp, *:81->80/tcp, *:53->53/udp
fyijaxnx2903   portainer_agent       global       2/2        portainer/agent:2.18.2          
ddrxmnjz9is4   portainer_portainer   replicated   1/1        portainer/portainer-ce:2.18.2   *:8000->8000/tcp, *:9000->9000/tcp, *:9443->9443/tcp

アクセス & 初期設定

Giteaにアクセスします。

初期設定画面が表示されました。
サイト名だけ変えてあとはデフォルト。

ユーザ登録は割愛して、リポジトリを作成します。

リポジトリにpush

ツール置いてあるディレクトリからcommit、pushします。
これはメイン機WindowsのWSL上にあります。

今は中身こんな感じ。
txtファイルはメモ、APIトークン、API投入コマンド系なので.gitignoreに入れておきます。
csvファイルは支払いデータですが一応管理対象にするか。(家の環境だからできることですね)

masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ ls
 ,      202301.csv   202304.csv   202307.csv   Mar.txt   command.txt          jul.txt   post.txt     transactionapi.py
 2021   202302.csv   202305.csv   202308.csv   apr.txt   feb.txt              jun.txt   salary.txt
 2022   202303.csv   202306.csv   202309.csv   aug.txt  'firefly token.txt'   may.txt   sep.txt
初期化

初回に表示されるアナウンスに沿っていきます。

masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ touch README.md
masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git init
Initialized empty Git repository in /mnt/c/Users/masashi/tools/Household-account/.git/
masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git checkout -b main
Switched to a new branch 'main'
masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        ,
        .gitignore
        2021/
        2022/
        202301.csv
        202302.csv
        202303.csv
        202304.csv
        202305.csv
        202306.csv
        202307.csv
        202308.csv
        202309.csv
        README.md
        transactionapi.py

nothing added to commit but untracked files present (use "git add" to track)
commit

addします。
txtが除外されてるので.gitignoreもOK。

masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git add *
The following paths are ignored by one of your .gitignore files:
Mar.txt
apr.txt
aug.txt
command.txt
feb.txt
firefly token.txt
jul.txt
jun.txt
may.txt
post.txt
salary.txt
sep.txt
Use -f if you really want to add them.

commitします。

masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git commit -m "first commit"
[main (root-commit) 6c897cc] first commit
 34 files changed, 1283 insertions(+)
()
リモートリポジトリ設定

giteaを指定。

masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git remote add origin http://10.0.1.1:3000/masashi/Household-account.git
masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git remote -v
origin  http://10.0.1.1:3000/masashi/Household-account.git (fetch)
origin  http://10.0.1.1:3000/masashi/Household-account.git (push)
push

これでやっとpush。

masashi@DESKTOP-HBP3520:/mnt/c/Users/masashi/tools/Household-account$ git push -u origin main
Username for 'http://10.0.1.1:3000': masashi
Password for 'http://masashi@10.0.1.1:3000':
Enumerating objects: 38, done.
Counting objects: 100% (38/38), done.
Delta compression using up to 4 threads
Compressing objects: 100% (37/37), done.
Writing objects: 100% (38/38), 17.53 KiB | 326.00 KiB/s, done.
Total 38 (delta 30), reused 0 (delta 0)
remote: . Processing 1 references
remote: Processed 1 references in total
To http://10.0.1.1:3000/masashi/Household-account.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

OK。

giteaにも登録されました。

執筆中に気づいたのですが謎の,ディレクトリをcommitしてしまいました。
後で消しておこう。

まとめ

ついに家にもgit環境が作成されました!
まあそんなに更新することはなさそうですが家計簿ツールのバージョン管理 + 保存先ができたので一旦安心。
今後はgiteaのデータを守らないといけませんね。

いきなりやらかしましたが自宅環境だからと不要ファイル、大切なファイルまでcommitしない様に意識したいところです。

前回ステージング環境を作ったことでこれのデプロイテストもできて手順が確立できたので簡単にデプロイでしました。
作ってよかった。

コンテナも増えてきたのでそろそろプロキシ導入も検討します。