好文集ChatGPT Plus¥119

AI専用ダッシュボードの作り方

文章目录

デスクの上に、Cursor や Claude Code、Codex、Gemini などのトークン消費量や利用枠の残量をリアルタイムに表示するAI専用ダッシュボード「Token Dashboard」を作ってみました。

キーボード奥などに置いておくことで、作業領域を圧迫せずに「今月のトークン消費量」や「リセットまでの時間」を一目で確認できます。

すぐに使ってみたい場合はこちら

アプリとしてそのまま使いたい場合は、下記を参照してください。

インストーラーを実行してディスプレイを USB に接続するだけで、ローカル集計や Token Monitor との連携ですぐに使い始められます。

──────────

どんなデバイスを使っているのか?

ハードウェアには、PC ステータス表示向けに設計された TURZX(Turing Smart Screen)製の USB スマートディスプレイを使用しています。

今回使ったモデル:9.2 インチ ウルトラワイド横長液晶

文章配图

*引用元: *TURZX 9.2 Inch Detail (turzx.com)

解像度 1920×462 px の横長バータイプ液晶を採用しました。キーボード奥やモニター下の隙間に収まり、複数の AI ツール(Claude、Cursor、Codex、Gemini など)のゲージを横一列に並べやすいレイアウトです。付属の USB Type-C ケーブル 1 本で給電とデータ通信の両方が完結します。

Amazon 等で販売されている外観が同等の製品は、内部ファームウェアや通信仕様の違いにより動作しない可能性があります。確実に動かしたい場合は動作確認済みの製品を推奨します。

ほかにも多様な形・サイズがある

TURZX には他にも様々なバリエーションがあります。

モデル形状 / 解像度特徴・イメージ
2.1 インチ 丸型円形 (480×480 px)水冷ヘッドや置き時計のようなラウンド液晶
3.5 インチ / 5 インチ長方形 (480×320 / 800×480 px)デスクの脇に置けるカードサイズ
8.8 インチ / 12.3 インチ横長バー型 (1920×480 / 1920×720 px)9.2 インチと同様の細長いウルトラワイドタイプ

文章配图

▲ 2.1 インチ丸型ディスプレイ。時計やタコメーターのようなデザイン

文章配图

▲ 3.5 インチ長方形ディスプレイ。スタンド付きでデスクに置きやすい

丸型ディスプレイで計器風にするアイデア

2.1 インチ丸型を並べ、AI ツールごとにスピードメーター風のアナログ計器を描画する構成も可能です。プロトコルは共通のため、画面解像度に合わせて画像を生成すれば同様に表示できます。

──────────

なぜサブモニターではなくこれなのか?

「普通のモバイルモニターを HDMI で繋げばいいのではないか?」という疑問に対し、専用ディスプレイには以下のメリットがあります。

他のWindowを隠さない

それこそ Token Monitor のようなツールはすでにありますが、画面の最前面に表示していると、他の情報を遮ってしまいます。でも、これは専用モニターなので、他のウィンドウの邪魔をしません

他のウィンドウに隠されない

逆に、別のツールによってこちらが隠されることもなく、いつでも視線を向ければ必ず同じ場所にみえます。

どうやって画面を出しているのか?(大まかな仕組み)

通常の映像信号(HDMI 等)ではなく、USB の Bulk 転送を使って画像ファイル(JPEG / PNG)をパケットとして直接流し込む仕組みです。

文章配图

一度画像を転送すると次の送信まで表示が保持されるため、値が変化したタイミングのみ送信すれば十分です。

送信パケットの中身

デバイスに送るデータは、512 バイトの固定ヘッダーと画像データ(JPEG / PNG)で構成されます。

パケット全体の構成

オフセットサイズ内容暗号化
0..503504 bytesコマンド、マジックナンバー、現在時刻、画像サイズDES-CBC(鍵: slv3tuzx)
504..5096 bytes予約領域(ゼロ埋め)平文(そのまま)
510..5112 bytes終端マーカー(0xA1, 0x1A)平文(そのまま)
512..可変長 (最大 1 MiB)送信したい画像データ本体(JPEG / PNG)平文(そのまま)

先頭ヘッダーの平文フォーマット(暗号化前)

暗号化する前の先頭 504 バイトのフォーマットは以下の通りです:

オフセット (byte)サイズ (bytes)項目名型・エンディアン内容・設定値
01コマンドuint8101: JPEG 送信、102: PNG 送信、10: 同期、11: 再起動
11予約uint80x00 固定
2..32マジックナンバーbyte[2]0x1A, 0x6D 固定
4..74当日経過ミリ秒uint32 (リトルエンディアン)当日 00:00:00 からの経過ミリ秒
8..114画像データ長uint32 (ビッグエンディアン)画像データのバイト長
12..503492パディングbyte[492]0x00 埋め

先頭 504 バイトを共通鍵 slv3tuzx で DES-CBC 暗号化し、終端マーカー(0xA1, 0x1A)と画像バイナリを連結して送信します。送信後は USB Bulk IN から 6 バイトの応答パケット([コマンド, 0xC8, タイムスタンプ])が返ります。

──────────

ミニマルなコードサンプル (Go)

TURZX 送信用パケットを組み立てる最小限の Go コード例です。

package main

import (
	"crypto/cipher"
	"crypto/des"
	"encoding/binary"
	"fmt"
	"time"
)

// 暗号化キー(ハードウェア共通)
var desKey = []byte("slv3tuzx")

// BuildPacket はコマンドと画像データから TURZX 送信用パケットを組み立てます
func BuildPacket(command byte, imagePayload []byte, now time.Time) ([]byte, uint32, error) {
	// 当日 00:00:00 からの経過ミリ秒を計算
	midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
	timestamp := uint32(now.Sub(midnight).Milliseconds())

	// 504 バイトの平文ヘッダーを用意
	header := make([]byte, 504)
	header[0] = command
	header[2], header[3] = 0x1A, 0x6D
	binary.LittleEndian.PutUint32(header[4:8], timestamp)
	binary.BigEndian.PutUint32(header[8:12], uint32(len(imagePayload)))

	// DES-CBC で暗号化 (鍵・IV ともに "slv3tuzx")
	block, err := des.NewCipher(desKey)
	if err != nil {
		return nil, 0, fmt.Errorf("暗号化の初期化に失敗しました: %w", err)
	}
	encrypter := cipher.NewCBCEncrypter(block, desKey)

	// 512 バイトヘッダー + 画像データのバッファを確保
	packet := make([]byte, 512+len(imagePayload))
	encrypter.CryptBlocks(packet[:504], header)

	// ヘッダー末尾の目印マーカー
	packet[510] = 0xA1
	packet[511] = 0x1A

	// 後ろに画像データをコピー
	copy(packet[512:], imagePayload)

	return packet, timestamp, nil
}

生成したパケットを WinUSB や libusb 経由でデバイスの Bulk OUT エンドポイントに書き込むことで、画面が更新されます。

もっと詳しく知りたいときは

排他制御や切断検知、詳細なプロトコル仕様は以下を参照してください。

全文完
查看原文