2025年 12月 27日

本を書く(LLMを使って)

最近、技術書をまとめていくつか出してみた。すべてLLM(Claude/Gemini/ChatGPT全部)を活用してながら書いてみてる。

LLMはまぁそれが主戦場なので文章は結構書いてくれる。けど、本として読んで価値あるものにしようと思うと、メインとなる背景の「考えかた(ないしは思想)」は、とにかく明確に定義する必要がある。つまり企画をしっかりやる重要さをより強く感じた。とにかく何を書きたいか、なぜ書こうと思ったかを自分と対話して明示する必要がある。

企画(設計)だけしっかりしてればLLM活用しても価値があるものが作れる気がしている。LLMに書かせてみて「それが面白いことじゃないんだよな」と否定と修正を繰り返すと、無意識のこだわりの輪郭が浮かびあがってくるように思う。

とはいえ、ニュアンスやトーンの指定は困難すぎるし、ロールを与えててもうまく意図や背景は汲み取ってくれないので、割とアホみたいな定型NG語尾集をつくったりする必要がある。

書きたいこと自体はやりだしてみると自分が思っていたよりあったりして (これら以外でもまだ書いてる)、やってるぶんには結構おもしろい。以下リンクです。(年末年始、順次無料キャンペーンを設定してあります)

アマゾンでの一覧

2025年 12月 08日

パスキー

パスキー設定できるサービスは設定しつつあるけど、いまだに結構なんとなく心理的負荷が高い。

  • 保存先
    • Google Password Manager?
    • Bitwarden?
    • 端末限定?
  • パスキーが失われたら?
    • 各サービスごとのリカバリポリシーを理解してからでないと最悪の事態になる
    • さすがにメアドでどうにかなることが多いが、パスキーとメアドは明示的に紐付かない


特に保存先について、ITよくわからんという人が理解できると思えない…… 基本的に普通の人は Google Password Manager に保存するのが現状でのベストだと信じている。理由は

  • 利用者が多い
  • 端末個別に保存するよりパスキーを失う可能性が低い
  • 現実的にメアドも Gmail なら、「Googleを信用する」としても問題が少ない
  • フィッシング対策としては十分

ただ、複数パスキーが設定可能なら Bitwarden も追加するようにしている。とにかくパスキーはリカバリーが問題で、サービスごとのリカバリ方法をいちいち調べるよりはパスキーを複数作ってロストしないことが最重要と考える。


実際は

1. セキュリティデバイス保存 (耐タンパ性)
2. スマフォ端末保存
3. クラウド保存

でレベルが違うわけだけど、現実的によく問題になっているフィッシングへの対策としては保存先はどれでもよく、利便性重視でよいと思う。

2025年 11月 04日

iGPU を活用して VRAM の節約

RTX 4070 (12GB VRAM) を使ってるけど、Stable Diffusion やら Photoshop や DaVinci Resolve などを使うと非常にカツカツでアプリケーションを終了させたりしてしのいでいる。あとほんの少しVRAMがあれば……と思うことも多々ある。これらのアプリが共有メモリに侵食してくると劇的にパフォーマンスが落ちるので……

ふと iGPU を有効にして微妙に VRAM を使用する Chrome ベースのアプリや Chrome 自体を iGPU に持ってくれば、dGPU から多少の VRAM を節約できるのではないかと考えた。のでやってみることにした。なおメインメモリは余っているものとする。

iGPUを有効にする

これまで何も考えずに iGPU は無効にしていたので、まずは UEFI メニューから iGPU を有効にして再起動。メインディスプレイ以外は iGPU 側に接続しなおした。

そのうえで、アプリケーションごとの設定も、特にパフォーマンスが必要ないものは iGPU を使うように。これは設定 > システム > ディスプレイ > グラフィックスからアプリケーションごとに設定できる。

細かく VRAM 使っているプロセスを指定していく。というかデフォルトを iGPU にできればいい気がするが……

Intel ドライバのアップデート

Chrome がどうもちょくちょくブラックアウトするので、Intel のディスプレイドライバを最新に

https://www.intel.co.jp/content/www/jp/ja/download/864990/intel-11th-14th-gen-processor-graphics-windows.html

Windows における iGPU と dGPU

dwm.exe (デスクトップウィンドウマネージャ) がウィンドウの合成を担当しており、これが各ウィンドウの内容をテクスチャとして合成してディスプレイへ出力している。

あるアプリケーションが iGPU を使ってレンダリングした結果を、dGPU に接続されているディスプレイで表示する場合、dwm が合成する際に PCIe 経由でのデータ転送が発生する(転送のオーバーヘッドがかかる)。

今回のように dGPU の VRAM 負荷を軽減するために iGPU(システムメモリ)にオフロードする場合は、PCIe 転送のオーバーヘッドとのトレードオフがあることに注意が必要。

dGPU の VRAM 負荷を軽減する戦略:

  • アプリ単位でのオフロード
    • GPU 指定機能を使い、軽量なアプリを iGPU に割り当てる
    • dGPU 接続のディスプレイに表示する場合は PCIe 転送のオーバーヘッドが発生
  • マルチディスプレイ構成の活用
    • メインディスプレイを dGPU に接続
    • サブディスプレイを iGPU に接続
      • サブディスプレイ上のアプリを iGPU 指定すれば、転送オーバーヘッドなしでオフロード可能

転送オーバーヘッドは画面領域×更新頻度に比例するため:

  • 大きな画面領域を高頻度で更新するアプリ(フルスクリーンゲーム、動画編集のプレビューなど)は転送コストが大きく、オフロードに不向き
  • 小さい画面や更新頻度が低いアプリ(テキストエディタ、ブラウザの静的ページなど)は転送コストが小さく、オフロードしやすい

具体例:

  • dGPU 優先: 重い3Dゲーム、3DCGレンダリング、大量のテクスチャを使うアプリ、AIモデル推論など
  • iGPU 可: Web ブラウザ、動画再生、コーディング環境、軽量な2Dアプリなど
2025年 10月 18日

Raspberry Pi から HDMI-CEC コントロール

サイネージ HDMI CEC 連携

カレンダーを表示するおうちサイネージ というのを作っていたがモニタの置き場がなくなってしまったので、テレビ画面に映すことにしてみた。

Google TV と Switch でしか使わないので、普段は基本的に Google TV のリモコンで操作している。しかし Raspberry Pi の HDMI を繋いで外部入力をそちらにすると、Google TV のリモコンからの操作 (HDMI CEC信号) をテレビ(SONY BRAVIA)が無視するという困った挙動になった。

試行錯誤してみると Raspberry Pi を HDMI CEC デバイスとして単に参加させる (以下のように)と、他の機器の CEC 信号も無視しなくなるようだった。

# 再生デバイスとして CEC デバイスのネットワークに参加
 cec-ctl --playback

他のデバイスのCEC信号を受けて自動表示

ここまではいいとして、カレンダーアプリはある程度自動的に起動してくれないと見ないため、Google TV のリモコンから電源をオフにすると、自動的に Raspberry Pi のカレンダーを表示する、という挙動にしたくなった。cec-ctl --monitor で HDMI CEC のイベントをストリーム取得できるようなので、これを利用してフックし、他の機器からのSTANDBYがきたら、Raspberry Pi 側に画面を切り替えるという処理を入れた。

 #!/usr/bin/env python3
 import subprocess
 import time
 import re
 import sys
 
 # ====== 設定値 ======
 CEC_ADAPTER_INIT_CMD = ["/usr/bin/cec-ctl", "--playback"]
 CEC_MONITOR_CMD = ["/usr/bin/cec-ctl", "--monitor"]
 TV_ON_CMDS = [
     ["/usr/bin/cec-ctl", "--to", "0", "--image-view-on"],
     ["/usr/bin/cec-ctl", "--to", "0", "--active-source", "phys-addr=4.0.0.0"]
 ]
 DEBUG = True
 # ====================
 
 
 def log(msg):
     """ログ出力(デバッグ時のみ)"""
     if DEBUG:
         print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)
 
 
 def run_cmd(cmd):
     """単発コマンド実行"""
     try:
         subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
         log(f"Executed: {' '.join(cmd)}")
     except subprocess.CalledProcessError as e:
         log(f"Command failed: {cmd} ({e})")
 
 
 def main():
     log("Initializing CEC adapter...")
     run_cmd(CEC_ADAPTER_INIT_CMD)
 
     log("Starting CEC monitor...")
     proc = subprocess.Popen(
         CEC_MONITOR_CMD,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT,
         text=True
     )
 
     last_device_standby = 0
 
     try:
         for line in proc.stdout:
             line = line.strip()
             if not line:
                 continue
 
             # 他のデバイスが STANDBY 送信
             if re.search(r"Received from Playback Device", line) and "STANDBY" in line:
                 log("Detected STANDBY from another playback device")
                 time.sleep(3)
                 for cmd in TV_ON_CMDS:
                     run_cmd(cmd)
 
     except KeyboardInterrupt:
         log("Interrupted by user")
     finally:
         proc.terminate()
         log("Monitor stopped")
 
 
 if __name__ == "__main__":
     if sys.version_info < (3, 6):
         print("Python 3.6+ is required", file=sys.stderr)
         sys.exit(1)
     main()

これを systemd にいれておく

sudo vi /etc/systemd/system/cec-init.service
 [Unit]
 Description=Configure HDMI CEC playback mode
 After=graphical.target
 Wants=graphical.target
 
 [Service]
 Type=oneshot
 ExecStart=/home/pi/cec.py
 RemainAfterExit=true
 
 [Install]
 WantedBy=multi-user.target
 sudo systemctl daemon-reload
 sudo systemctl enable cec-init.service
 sudo systemctl start cec-init.service
 
 sudo systemctl status cec-init.service 
 ● cec-init.service - Configure HDMI CEC playback mode
      Loaded: loaded (/etc/systemd/system/cec-init.service; enabled; preset: enabled)
      Active: activating (start) since Sat 2025-10-18 14:59:08 JST; 11min ago
    Main PID: 2820 (python3)
       Tasks: 2 (limit: 754)
         CPU: 371ms
      CGroup: /system.slice/cec-init.service
              ├─2820 python3 /home/pi/cec.py
              └─2823 /usr/bin/cec-ctl --monitor
 
 Oct 18 14:59:08 sinage systemd[1]: Starting cec-init.service - Configure HDMI CEC playback mode...
 Oct 18 14:59:08 sinage cec.py[2820]: [14:59:08] Initializing CEC adapter...
 Oct 18 14:59:09 sinage cec.py[2820]: [14:59:09] Executed: /usr/bin/cec-ctl --playback
 Oct 18 14:59:09 sinage cec.py[2820]: [14:59:09] Starting CEC monitor...
 Oct 18 15:00:42 sinage cec.py[2820]: [15:00:42] Detected STANDBY from another playback device
 Oct 18 15:00:45 sinage cec.py[2820]: [15:00:45] Executed: /usr/bin/cec-ctl --to 0 --image-view-on
 Oct 18 15:00:45 sinage cec.py[2820]: [15:00:45] Executed: /usr/bin/cec-ctl --to 0 --active-source phys-addr=4.0.0.0
 Oct 18 15:08:43 sinage cec.py[2820]: [15:08:43] Detected STANDBY from another playback device
 Oct 18 15:08:46 sinage cec.py[2820]: [15:08:46] Executed: /usr/bin/cec-ctl --to 0 --image-view-on
 Oct 18 15:08:46 sinage cec.py[2820]: [15:08:46] Executed: /usr/bin/cec-ctl --to 0 --active-source phys-addr=4.0.0.0
2025年 10月 16日

NASの10Gbps接続を10GBASE-SR(光ファイバー)に

2021年から使っているNASのHDDの音が気になるようになってしまった。作業部屋を移動したからかもしれないがなんとかすることに。

玄関に追い出す

箱に入れるとかも考えたが、同じ部屋に置いておくのは無理という結論にいたり、玄関に置き場所を確保した。

そのうえで 10Gbps の LAN をどうするかという問題に対処することに。

10Gbps 接続の選択肢

今までは 1m の DAC (ダイレクトアタッチケーブル) を使っていたが、玄関まで配線しようとすると 7m ぐらい必要。あんまり長い DAC よくなさそうだし高いので、この時点で排除して2択

  • AOC (Active Optical Cable)
    • 両端 SFP+ でケーブルは光ファイバ。光コネクタがなくて直結している。DACみたいに使える
    • 若干安い
  • 10GBASE-SR トランシーバ×2 + 光ファイバーケーブル
    • 一番汎用性が高い。光コネクタとかを理解する必要がある

一応 10GBASE-T のトランシーバ×2 + CAT6 LAN ケーブルという選択肢もあるかもだけど、消費電力は高いしコストも高いし信頼性も低いので新規導入では選択肢に入らないと思う。

結論としては 10GBASE-SR にした。

10GBASE-SR と光コネクタと光ファイバー

10GBASE-SR の SR は Short Range の略。MMF(マルチモードファイバー)というコアが比較的太くて機械的精度要求が低い光ファイバーを使い、300mぐらいまでの通信に使えるものらしい。意外とコスト低め。家庭内では十分

SFP+ の場合、光コネクタは LC を使うのがデファクトスタンダードらしい。

光ファイバーは OM3、OM4、OM5 などがマルチモードファイバーの規格名のようだ。数字が大きいほど性能が良いが、OM3でも十分なので一番安いのを選べばよい。つまり LC/LC OM3 となっている光ファイバーを買えばいい。

光ファイバーケーブルの接続

送受信で別々のファイバーを使うので、2本必要。duplex と書かれたものを買う。両端でペアになるように部品がついている。そしてペアのどっちがどっちのケーブルかわかるようになっている。そしてこれらはクロス接続する必要がある。

ただ今回買った光ファイバーは最初からクロス接続になるように配線されていた。買ってそのまま挿せばいいだけだった。

問題なくおわった

何もハマることなくすんなり接続できた。SFP+ はベンダーロックとかがあったりするので不安要素が多いのだけど、今回は大丈夫だった。

光ファイバーは最小曲げ半径が 7.5mm らしく意外を曲げられるようだ? しかしなんとなく銅線よりも取り回しに気をつかってしまう。

これで電気的に絶縁されて接続されてると思うと気分が良い

2025年 09月 04日

月1万円の支出削減は資産400万円に相当する

経済的独立 (FIREのFIの部分)の文脈では「月1万円の支出削減は資産400万円を増やすのと同じ効果」があるといえる。

これは いわゆる「25倍ルール」 ないし 「33倍ルール」 から考えられる。

25倍ルール・33倍ルールとは

25倍ルールは、年間支出の 25倍の資産 があれば、資産の4%を毎年取り崩しても一生暮らせるという目安。「4%ルール」に基づくもの。

より安全に見積もりたい場合、資産の3%しか取り崩さないとすると、必要資産は 年間支出の33倍。国内だと税制やらなんやらで3%で計算しろとかなんとか。

たとえば年間400万円の支出 (税金や社会保険料なども含む) がかかるとすると

  • 25倍ルール → 1億円(400万 × 25)
  • 33倍ルール → 1.32億円(400万 × 33)

で無収入でも破綻しなくなる (破綻するかどうかは実際は確率の問題だが)

月1万円削減が資産400万円に相当する、とは

月1万円の支出を減らすと

  • 月1万円の支出削減 → 年間で12万円の削減
    • 1万円 × 12ヶ月 = 12万円
  • 25倍ルールを適用すると、必要な資産は:
    • 12万円 × 25 = 300万円
  • 33倍ルールを適用すると:
    • 12万円 × 33 = 396万円(約400万円)

月額1万円を得るのために400万円の資産が必要、ということは、逆に見れば「月1万円の支出を減らすと、300〜400万円の資産を持っているのと同じ効果」といえる。

なぜこの考え方が重要なのか?

資産を300〜400万円増やすのは自明に大変だが、月1万円の削減なら比較的簡単である。見方を変え、月あたりの1万円には資産換算で400万円という価値があると感じることができれば浪費により強いブレーキをかけることができる。

逆に月1万円の収入には400万円の資産と同等の効果があるともいえる。キャッシュフローの重要さが身に染みる。

2025年 08月 30日

人間のファイナンシャルプランナーよりLLMのほうがマシだよね

ファイナンシャルプランナーって信用できないじゃないですか。信用できるかどうか判断するためには相手と同等以上の金融知識が必要になる。人間には利害関係があり、不動産屋と金融屋は特に倫理観がないので、利害関係がない分、たとえハルシネーションがあったとしてもLLMのほうがマシだと考える。

ということでMoneyForward ME の家計簿データをLLMに診断してもらうということを考える。

MoneyForward ME の家計簿データを一括でダウンロードするブックマークレット

https://gist.github.com/cho45/e0ed3e408f87ab9a5c29e2d612db82ab

過去1年分の取引履歴CSVデータを結合したものと、資産推移を以下のような形式で一括でダウンロードする。transactions 以下は構造化されていないCSVがそのまま入っている。

これ自体も Claude Code に指示しつつ書いたのでほぼ手は入れてない。

### JSON構造

```json
{
  "exportDate": "2024-08-29",
  "period": {
    "from": "2023-09",
    "to": "2024-08"
  },
  "monthlyAssets": [...],
  "transactions": {...}
}
```

### フィールド詳細

#### `exportDate`
- データを取得した日付(YYYY-MM-DD形式)

#### `period`
- `from`: 取得期間の開始月(YYYY-MM形式)
- `to`: 取得期間の終了月(YYYY-MM形式)

#### `monthlyAssets`
月末時点の資産データの配列。各要素の構造:
```json
{
  "date": "2024-08-31",
  "assets": {
    "現金・預金": 1000000,
    "投資信託": 500000,
    "株式": 300000,
    "その他": 50000
  }
}
```

#### `transactions`
取引履歴データ:
```json
{
  "format": "csv",
  "encoding": "utf-8",
  "successCount": 12,
  "failedMonths": [],
  "rowCount": 365,
  "data": "\"計算対象\",\"日付\",\"内容\",\"金額(円)\",\"保有金融機関\",\"大項目\",\"中項目\",\"メモ\",\"振替\",\"ID\"\n\"1\",\"2024/08/25\",\"給与 ABC株式会社\",\"300000\",\"△△銀行\",\"収入\",\"給与\",\"\",\"0\",\"abc123def456ghi789\"\n..."
}
```

- `successCount`: 正常に取得できた月数
- `failedMonths`: 取得に失敗した月のリスト
- `rowCount`: 取引データの行数(ヘッダー除く)
- `data`: 実際のCSVデータ(Shift-JISからUTF-8に変換済み、ダブルクォート付き)

### CSVデータフォーマット詳細

`transactions.data` に含まれるCSVは以下の構造です:

#### ヘッダー行
```
"計算対象","日付","内容","金額(円)","保有金融機関","大項目","中項目","メモ","振替","ID"
```

#### データ行の例
```
"1","2024/08/29","コンビニA店","-500","△△銀行","食費","食料品","","0","abc123def456"
"1","2024/08/28","給与 ABC株式会社","250000","△△銀行","収入","給与","","0","def456ghi789"
"1","2024/08/27","電力会社","-8500","○○カード","水道・光熱費","電気代","","0","ghi789jkl012"
"0","2024/08/26","証券会社 積立","30000","△△銀行","未分類","未分類","","1","jkl012mno345"
```

#### 各列の詳細

1. **計算対象**: 家計簿の計算に含めるかの判定(1=計算対象、0=計算対象外)
2. **日付**: YYYY/MM/DD形式の取引日
3. **内容**: 取引の説明文(店舗名、サービス名など)
4. **金額(円)**: 取引金額(収入は正数、支出は負数)
5. **保有金融機関**: 連携している金融機関名
6. **大項目**: MoneyForwardの大分類カテゴリ
   - 例:収入、食費、住宅、水道・光熱費、通信費、交通費、税・社会保障、日用品、健康・医療、教養・教育、趣味・娯楽、衣服・美容、その他、未分類
7. **中項目**: 大項目の下位分類
   - 例:給与、食料品、家賃・地代、電気代、ガス・灯油代、インターネット、電車、所得税・住民税など
8. **メモ**: ユーザーが手動で入力したメモ(空白の場合が多い)
9. **振替**: 振替取引の場合は1、通常取引は0
10. **ID**: MoneyForward内部のユニークな取引ID

LLMへ指示をするプロンプト

家庭状況によって必要な診断が異なるので、ここに関しては↑のフォーマット情報を利用してプロンプトを生成するコードをLLMに書かせるのがよいと思う。

例えば最終的なプロンプトが以下のようになるようなコード自体をLLMに書かせる。

あなたは家計の浪費防止に特化したファイナンシャルアドバイザーです。以下のデータを基に「無駄な支出の特定」と「浪費防止策」を重点的に分析してください。

【家庭状況】
- 世帯主: 38歳
- 家族構成: 配偶者(38歳)・子供1人 (11歳)
- 住居: 首都圏、賃貸マンション(家賃月xx万円)
- 投資方針: 積極的
- 交通: 電車中心

妻と自分とで完全に財布が別で、厳密ではないが支出種別ごとに支払い者が違います。
食費や服飾費が妻、それ以外は自分という分類です。

<以下フォーマットされた分析データ>
【資産推移分析】
...

【月別収支推移】
...

【カテゴリ別年間支出】
...

【異常値・変動分析】
...

**統計的外れ値(大口支出上位10件)**
...

**カテゴリ別支出分布統計**
...

【浪費防止分析を実施してください】
1. **異常値に基づく浪費特定**: 統計的外れ値や前月比異常値から無駄な大口支出を特定。重複パターンから習慣的な無駄を抽出
2. **変動性からのリスク分析**: 月別変動係数の高いカテゴリから予算コントロールが困難な項目を特定し、安定化策を提案
...

これを ChatGPT なり Gemini なり Claude にコピペする。データからわからない前提はしっかり書いておかないと適切にならない。

2025年 08月 29日

VALETON GP-5 + 自作MIDIデバイスたち

VALETON GP-5 というマルチエフェクタを買ってみた。小さいながら凝っていて、アンプシミュレータも内蔵しているのでヘッドフォン直結やスピーカーシステム直結で使える。

これは USB 5V のバスパワーで動くので、スマホに繋げば電源供給をスマホ側でできる。
なので、最小構成では GP-5 + スマホだけでそこそこ良い運用ができる。

WebMIDI Switcher

https://github.com/cho45/webmidi-switcher

GP-5 本体のボタンは「長押し」にチューナー機能が割り当ててある関係で、エフェクトが切り替わるタイミングがボタンを離したときになってしまう。これが嫌なので、別途スイッチを用意したい。

GP-5 は USB MIDI コントロールができ、スマホ側は WebMIDI API から GP-5 に MIDI 信号をおくれる。

スマホから電源供給もしつつ、スマホ自体をフットスイッチにできると嬉しいので、そういうウェブアプリを作った。

PicoMIDI Switch

https://github.com/cho45/picomidi

しかしながら、スマホを足で踏むのは割とむずかしいし抵抗があるので、市販のフットスイッチを流用する方法を考えた。

TRSプラグを利用するただのモーメンタリなフットスイッチが売っているので、これを利用する。

Raspberry Pi Pico で USB MIDI デバイスを作って、TRS → USB MIDI 変換を行っている。スイッチへの MIDI 信号の割当も WebMIDI API でできるようなウェブアプリを作ってある。余計なアプリはいらない。

スマホ側の WebMIDI Switcher には MIDI メッセージを中継する機能をつけてある。これでハブを経由してそれぞれ接続すればコントロールできるようになっている。

かなり装備が軽く、かつフットスイッチありなので、いいんじゃないか

M-VAVE Chocolate Plus は国内では使えません……

「MIDI フットコントローラ」とかで検索するとよくでてくる M-VAVE Chocolate Plus というのがある。4スイッチで USB Host にもなれ、BLE でも接続可能で 3000円代と安い。amazon.co.jp でも売ってるので(リンクは出さないが)、気にはなっていた。

改造したらなんとかならんかなと重い、Aliexpressで買ってみて、改造を試みてみた。

「技適未取得機器を用いた実験等の特例制度」を申請して自己責任で期間限定で合法となる、はず。

微弱無線局未満を目指してみたけど、設備がないと微弱無線局の基準を満たしているかは釈然とせず、結局安心して使えるようにはならないという結果だったので、やっぱ簡単な改造では使えないなというお気持ちになった。


なお FCC ID は 2ARCP-CHOCOLATEPLUS のよう (https://www.fcc.gov/oet/ea/fccid )。

2025年 08月 07日

おうちサイネージ (食卓カレンダー)

家族の予定は基本的に共有カレンダーで管理しているが「みんなが見れる用」として食卓近くに卓上アナログカレンダーが置いてあり、何年もの間、二重管理になっていた。ずっと気になってはいつつも、まぁ運用できてるし、単にカレンダー表示するだけでもまぁまぁ面倒なのでそのままだったが、この度 Raspberry Pi でサイネージを作ることにした。

構成はシンプルで、15インチの 1080p モニタと、余っていた Raspberry Pi 3 B (WiFi付き)

CUIUIC モバイルモニター 15.6インチ ポータブルモニター モバイルディスプレイ 1920x1080FHD IPS液晶パネル 400Nits 100%広色域 Tpye-C/mini HDMI/スピーカー内蔵 PS4/PS5/XBOX/Switch/PC/Macなど対応 保護カバー付き - CUIUIC

CUIUIC

4.0 / 5.0

できること

  • Google Calendar の表示 (ほぼ Google Calendar互換の表示をする。複数日とかも)
  • 天気予報 (気象庁のXMLから取得している)
  • 時計 (西暦・和暦・日付曜日時間)

10分ごとに内容を更新する。

https://github.com/cho45/my-sinage

モニタ解像度

Raspberry Pi のほとんどは 1080p までしかスムーズに出力できないので、あまり高精細なディスプレイを買ってはいけない。1920x1280 のモバイイルディスプレイをいくつか持っているけど、モニタとの相性もあるのか、まともに表示させることができなかった。素直になってください。1080pのモニタを買えばいいです。(2日ぐらい無駄にした)

15インチのモニタは微妙にデカいけど、カレンダーをフルで表示させるならこのぐらい大きくてもいいかなという印象。捨てるときのこと考えるとあんまり大きいもの買いたくないのよね……

モニタの固定

「モバイルモニタ」カテゴリのものは固定方法が考えられてない。VESAマウント? そんなものはない。ただのスレートです。

ということで3Dプリンタでスタンドを作り、棚板にビス止めすることにした。安定。

ウェブアプリ

認証情報を保持してカレンダーの画面を出すウェブサーバを立てている。これは Raspberry Pi 上ではなく、QNAP 上の Container Station で docker image を動かしている。QNAP はうちだとIP アドレス固定で使っているので管理しやすい。

ディスプレイが繋がっているサイネージ用の Raspberry Pi はブラウザでURLを開くだけ。

スマフォとかから管理画面を開いて強制リロードのシグナルを送ったりできるようにしてある。ウェブアプリ側を更新したときに呼ぶ用。

開発

ほぼほぼ Claude Code にやらせた。ウェブアプリ、ちょいちょいクソコードは書くものの、特にクライアントサイドを書かせるのは割とすんなりやってくれる。

サーバサイドはなんか結構ガイドしないとちゃんとやってくれない。

夜中は消灯

cron で 02:00 に画面を消灯、06:00 に点灯という制御を入れてある。

最近の Raspberry Pi OS (bookworm) は labwc というWayland コンポジタ実装が使われているが、あんまりこれの情報がないのでめんどくさい。

XDG_RUNTIME_DIR=/run/user/1000
 
 # 02:00 にオフ
 0 2 * * * /usr/bin/wlr-randr --output HDMI-A-1 --off
 # 06:00 にオン
 0 6 * * * /usr/bin/wlr-randr --output HDMI-A-1 --on --mode 1920x1080

この手のものはいかに運用を楽にするかというのが問題。「うまく動かない」場合にメンテできるのが自分しかいないからだ。