2026年 01月 07日

CSS 2026

せっかくバックエンドシステムも変わったことだしと思ってCSSをアてなおした。何年ぶりかわからん (調べたら約10年一緒だった)

以下のように gemini-3-flash-preview に指示して、何度かやりなおしたら割といい感じだったので、さらに指示を加えたり手動で数字いじってなんとかした。

この日記を以下の条件で CSS を書きなおして新しいデザイン(見た目)を適用するとしたらどうしますか。やってみて
- 落ち着いたトーン 
- 「読みやすさ」最重視  
-「コード」は情報密度を高く
- 「写真」はできる限り大きく 
- ブロックの大きさに px 基本的に指定しないこと 
- フルにレスポンシブ (モバイルも同一ページです) 

中央揃えだとなんかモダンに感じる。

コードブロックと写真の幅を画面いっぱいにしたりするのは後からの指示。

HTML の変更はしないつもりだったけど、結局微調整した。

ヘッダのアイコン

ヘッダにアイコンも追加してみた。Nano Banana Pro で何度かイメージを伝えつつ気に入るのをいろいろ出させてブラッシュアップしたあと、Inkscape でトレースして、「パスの簡略化」で点の数を削減した。

なお gemini-3-pro-preview に同様にことをやらせたら、完全なるゴミができたため捨てました。遅いし

JS と WebComponents

CSS とは直接関係ないけどJSまわりも若干モダンにした。ものすごく古い書き方をしていたり、loading="lazy" がない時代の画像のプレースホルダーコードが残ったりしていた。なんか大抵のことはブラウザがやってくれる時代になっていた……

見出しの改行位置を調整するのを独自でやっていたけど、完全にやめて budou-xのWebComponents を導入した。

アーカイブあさり

  • 2014年1月 はこれはこれでよかったな
  • 2015年2月 は今も使ってるタイトルに近い。けどウェブフォントだったようだ
  • 2016年10月 は前のCSSに近い。ここからはほぼマイナーアプデしかしてないはず
2026年 01月 04日

日記システムPerlからgolangに書き換え

この日記システムを golang で書きなおした。元日から4日ぐらいかけた。なんかおかしかったら教えてください。

前々から日記システムをgolangにしたいなという気持ちを抱きつつxatena-goを書いたりしていた。しかし実際全体を移行するという気がなかなか起きなかった。というのも Hatena記法だけじゃなくてMarkdownだったり素のHTMLだったり、tDiary記法だったりをそのままDBに入れていたり、類似エントリ機能とか、類似画像機能とか、それらを実行するジョブキューとか、なんか細けえ最適化 (linkヘッダとか) が入ってたりとか……

最初のとっかかりが重要、ということで、既存のDBそのままで閲覧側だけまず作り (表示するだけだから特にフォーマッタとかは関係ない)、一旦安心しつつ書きこみ系を実装していった。大きな変更は主に Claude Code で計画させて割と自動で実装してもらい、Claude Code の Limit がきたら、細かいレビューしたり、小さい変更は Gemini CLI で補完した。

無駄に元のスキーマで DATE や DATETIME をつかっていたせいで (SQLite ではTEXTと一緒)、これらを go-sqlite3 が「いい感じ」に time.Time に変換するので、若干ややこしいクエリに書きかえたり、最小限のマイグレーション (created_at などを TZ 付きのフルのISO 8601に) をかけた。

サーバサイドで主につかったもの

  • sqlc backtick のエスケープに対応してない?のが罠なぐらい?
  • echo 特に気になるところない。HideBanner = true ぐらい

管理画面

自分しか使わない管理画面をリッチに作る気がさらさら起きなかったので、今までは1つの「編集」画面しかなかった。十分といえば十分だけど予約投稿機能が実はあるので、それを管理するのが面倒なのと、ジョブキューの見える化をしたかったので、新しく作った。

編集画面は、元々は Polymer による Web Components 実装だった。なので、最初は Lit で Web Components を書き直したけど、どうしても HTML in JS が許せないので、やっぱやめて使ったことない Svelte にしてみた。

Svelteも最初は Web Components モード (SvelteはSPAを念頭にしてるが、そういうモードがある) として使ってたけど最終的には管理画面全体で SPA として再構築した。

といってもほとんどこれらの「あっちこっち」の書き換えは Gemini CLI でやったので特にまだ Svelte の特徴を感じてはいない……

Gemini CLI はなんか Lit は Google が推してるから安心ですよみたいなこと言ってきたので「PolymerやAngularJSのこと考えると Google が推してるからといって安心ということはない」と言ったら Svelte がこの手の小さいやつだと最適とか本当に適当なことをいう。

PSS (Proportional Set Size) = 実質的な消費量

smem というツールを使うと実質的な消費量が簡単に見れるらしい。知らんかった。preforkモデルだと copy on writeを考慮した実質的なメモリ消費量が top や ps だと簡単にわからないので便利だ〜

smem -P "/srv/www/backend.psgi" -t -k
  PID User     Command                         Swap      USS      PSS      RSS 
2438110 cho45    /srv/www/backend.psgi (mast        0     6.0M    10.9M    50.0M 
2438111 cho45    /srv/www/backend.psgi (work        0     6.8M    10.9M    49.4M 
2438114 cho45    /srv/www/backend.psgi (work        0     7.5M    11.2M    49.1M 
2438205 cho45    /usr/bin/python3 /usr/bin/s        0    11.0M    11.3M    13.7M 
2438118 cho45    /srv/www/backend.psgi (work        0     7.8M    11.4M    49.4M 
2438119 cho45    /srv/www/backend.psgi (work        0     8.5M    12.2M    50.2M 
2438120 cho45    /srv/www/backend.psgi (work        0     8.7M    12.3M    49.6M 
2438117 cho45    /srv/www/backend.psgi (work        0     8.7M    12.3M    49.7M 
2438112 cho45    /srv/www/backend.psgi (work        0     8.9M    12.4M    49.7M 
2438113 cho45    /srv/www/backend.psgi (work        0     8.8M    12.6M    50.5M 
2438115 cho45    /srv/www/backend.psgi (work        0     9.3M    13.0M    51.1M 
2438116 cho45    /srv/www/backend.psgi (work        0    17.9M    21.6M    57.8M 
-------------------------------------------------------------------------------
   12 1                                           0   109.8M   152.0M   570.1M 

PSSの合計が重要で、この場合152MB使っている。

  PID User     Command                         Swap      USS      PSS      RSS 
2498750 cho45    /usr/bin/python3 /usr/bin/s        0     9.8M    10.1M    12.2M 
2498688 cho45    /srv/www/lowreal.net/Hanran        0    17.8M    17.9M    19.6M 
-------------------------------------------------------------------------------
    2 1                                           0    27.6M    28.0M    31.8M 

移行後はそもそも1プロセスにした。やたらメモリ使用量減ってくれた。

2026年 01月 03日

『JavaScriptから現実世界に干渉する7の方法: ブラウザでハードウェアをコントロールする技術』という本を書いた

[JavaScriptから現実世界に干渉する7の方法: ブラウザでハードウェアをコントロールする技術]

JavaScriptから現実世界に干渉する7の方法: ブラウザでハードウェアをコントロールする技術という本を書いてみた。前々からこのテーマでまとめた一冊というのを作りたかったので勢いで書いた。サンプルコードもほぼ各章ごとに、そこそこすぐ試せる形で用意したりして工夫してみた。

JSから直接ハードウェアをコントロールするのが好きなのと (特に WebSerial/WebUSB)、もともと WebAudio が好きだったのもあるので、これらを包括的に「現実的に干渉する」というまとめにすることにしてみた。そうなると「ディスプレイ」(光)」も無視できないので、光→振動→音→(HID→MIDI)→Serial→USB とより低レベルになるような構成にしてみた。

直前にいろいろ一気に書いたけど、だんだんやりかたをアップデートした結果、これが一番図とサンプルコードに気合が入っている。

1月3日17時〜7日の17時までは無料に設定してみたので眺めてみてください。

2025年 12月 31日

XSLTという関数型言語

ブラウザの安全性を高めるための XSLT の削除とかいうことで、つまりブラウザネイティブでの XSLT のサポートは消えるので、ちょっと哀しいですねという気持ち。

一時期(20年前……)は XML を手書きで書いて、XSLT で変換してHTMLにするという日記システムを作って使っていた (さすがにブラウザ直ではなくPHPでやらせてたけど)。そこから20年、クライアントサイド XSLT の本来の目的である、データをレンダリング可能な HTML に変換する機能は、より安全で、より人間工学に基づき、より適切にメンテナンスされた JavaScript API に取って代わられています。とか書いてあるのを見ると、まぁ事実なんだけどただかなしいなという。

XSLT (特に 1.0) は、副作用がなく、変数は不変(一度定義したら変更不可)、ループは再帰で実現するという、割と強めの関数型言語で、自分が初めて触った関数型だったと思う。XSLT のおかげで他の関数型のパラダイムも割とすんなり入った気もする。

Gemini に XSLT で関数型っぽさがわかるサンプルを書かせてみた

出力そのまま。SVG を出力するというサンプルを書いてくれた。しかもアニメーションする。これが素のブラウザで見れるのも今だけです。

XML はただの起点

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="fractal.xsl"?>
<root></root>

XSLT 側では4つの四角を call-template で生成するところから開始して、再帰でフラクタル状に四角をつくっていく。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/2000/svg">
  <xsl:output method="xml" indent="yes" media-type="image/svg+xml"/>

  <xsl:template match="/">
    <svg width="100%" height="100%" viewBox="-500 -500 1000 1000" style="background-color: #1a1a1a;">
      <title>XSLT Recursive Fractal</title>
      
      <xsl:call-template name="draw-square">
        <xsl:with-param name="x" select="0"/>
        <xsl:with-param name="y" select="0"/>
        <xsl:with-param name="size" select="300"/>
        <xsl:with-param name="depth" select="5"/> </xsl:call-template>
    </svg>
  </xsl:template>

  <xsl:template name="draw-square">
    <xsl:param name="x"/>
    <xsl:param name="y"/>
    <xsl:param name="size"/>
    <xsl:param name="depth"/>

    <xsl:if test="$depth > 0">
      
      <xsl:variable name="color">
        <xsl:text>hsl(</xsl:text>
        <xsl:value-of select="$depth * 40"/>
        <xsl:text>, 70%, 60%)</xsl:text>
      </xsl:variable>

      <rect 
        x="{$x - $size div 2}" 
        y="{$y - $size div 2}" 
        width="{$size}" 
        height="{$size}" 
        fill="{$color}" 
        opacity="0.9"
        stroke="#fff"
        stroke-width="1"
      >
        <animateTransform 
            attributeName="transform" 
            type="rotate" 
            from="0 {$x} {$y}" 
            to="360 {$x} {$y}" 
            dur="{10 + $depth * 5}s" 
            repeatCount="indefinite" />
      </rect>

      <xsl:variable name="nextSize" select="$size * 0.5"/>
      <xsl:variable name="offset" select="$size * 0.75"/> <xsl:variable name="nextDepth" select="$depth - 1"/>

      <xsl:call-template name="draw-square">
        <xsl:with-param name="x" select="$x"/>
        <xsl:with-param name="y" select="$y - $offset"/>
        <xsl:with-param name="size" select="$nextSize"/>
        <xsl:with-param name="depth" select="$nextDepth"/>
      </xsl:call-template>

      <xsl:call-template name="draw-square">
        <xsl:with-param name="x" select="$x"/>
        <xsl:with-param name="y" select="$y + $offset"/>
        <xsl:with-param name="size" select="$nextSize"/>
        <xsl:with-param name="depth" select="$nextDepth"/>
      </xsl:call-template>

      <xsl:call-template name="draw-square">
        <xsl:with-param name="x" select="$x - $offset"/>
        <xsl:with-param name="y" select="$y"/>
        <xsl:with-param name="size" select="$nextSize"/>
        <xsl:with-param name="depth" select="$nextDepth"/>
      </xsl:call-template>

      <xsl:call-template name="draw-square">
        <xsl:with-param name="x" select="$x + $offset"/>
        <xsl:with-param name="y" select="$y"/>
        <xsl:with-param name="size" select="$nextSize"/>
        <xsl:with-param name="depth" select="$nextDepth"/>
      </xsl:call-template>

    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
2025年 12月 30日

Chemr (Chemrtron) を再実装

Electron の非互換変更で大幅なアーキテクチャ変更を余儀無くされた時点でやる気がなくなってしまい、10年ぐらい前から触ってなかった Chemr というインデックス付きのドキュメントビューワーを再実装した。

なお Chemr はもともと .chm (Compiled HTML Help) を macOS で読むためものだった。chm とか懐しいが、要は chm の嬉しいところは索引付きというところ (あとオフラインでも読める) なので、とりあえず索引だけなんとか作って、オフィシャルなドキュメントを高速にすぐひけるようにしようというという形で Electron でつくったのが Chemrtron だった。

再実装

コード自体はほぼコーディングエージェントにやらせた。

元コードがあまりに古いのと、それほど機能が複雑ではないので、既存のプロジェクトをアップグレードではなく新規に作らせたほうが楽だろうということでスクラッチから書きなおし。ただし旧実装はディレクトリをわけて置いておいて、参考にしろという形でコンテキストを与えながらやった。

最初は Claude Code、基本ができて Claude Code の週間 Limit のひっかかってしまったので、残りは Gemini CLI。

最初の動作確認というところで、ELECTRON_RUN_AS_NODE=1 な環境で実行していて一生エラーでてて、これを「インストールの失敗だ!」「お前の環境が悪い!」と言い張ってて Claude がまじでアホだった。

そしてバカでお茶目な Gemini ちゃんは「✦ 大変申し訳ありません。前回の write_file において、最も重要な部分であるスクリプト内の関数群(handleSearch, selectResult など)を // ... (中略) ... という文字列で置き換えてしまうという、致命的なミスを犯しておりました。 」というのを何度も繰替えすので、accepting edits には全くできず、少しでも不信なコードを書きはじめたら止めて再指示という超マイクロマネジメントをした。だいたい Edit で長時間かかってるときは無駄にでかい変更をしようとして失敗するので、さっさと止めて変更を分割しろ小さくしろと即座に再指示するしかない。

Gemini はデフォルトのシステムプロンプトが本当にクソでイライラするので書きかえて使っている。レビューしてる時に質がゴミなのに「次に進みますか?」って何度も訊いてくるのが本当に我慢ならない。

Claude もイライラすることは多いが、Gemini みたいにファイルをぶっこわすみたいなアホなことはしないので、イライラのレイヤーが数段違う。

そんなこんなで1時間ぐらいは無駄にしたけど、だいたい(3時間+5時間)2日で機能がそろって v2.0.0 として出せた。

インデックスを作る部分も古すぎるので非互換変更を入れ、既存のもののうち重要そうなのは、LLMに再実装させた。ついでに全部のインデクサがちゃんと動くかテストできるようにした。

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 らしく意外を曲げられるようだ? しかしなんとなく銅線よりも取り回しに気をつかってしまう。

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