1 ポイント 投稿者 GN⁺ 2024-10-05 | 1件のコメント | WhatsAppで共有
  • 毎朝スマートフォンでニュースやソーシャルメディアを延々とスクロールする習慣を減らすため、ドットマトリクスプリンターでパーソナライズされた紙のフロントページを毎日印刷
  • 構成は Star NP-10、Raspberry Pi Zero W、パラレルポート-USBアダプター、電源装置とシンプルで、Piではプリンターを /dev/usb/lp0 デバイスとして扱う
  • 古いプリンターは一般的なUnicodeではなく、Code Page 437に近い制限された文字セットを受け付けるため、PHPで16進値を直接送って罫線・ボックス・温度記号を印字
  • データは Open-Meteo、twelvedata、NYTimes、Reddit JSONから取得し、天気・株価・ニュース見出し・Reddit投稿を紙幅に合わせて整形
  • cronで毎日午前8時ごろ自動実行され、1枚に収まる有限のニュースがWebサイトやアプリの無限スクロールの代わりになる

画面の代わりに紙のフロントページを作る

  • 朝にスマートフォンを開いて複数のニュースサイトやソーシャルメディアをスクロールする習慣を減らしつつ、最新情報も確認したかった
  • eBayで購入したドットマトリクスプリンターを活用し、毎日用意されるカスタム フロントページ を印刷する方式で実現
  • 全ソースコードは GitHub repo で公開されている

ハードウェアの選定と接続

  • 必要な構成品は比較的シンプル
  • 使用したプリンターは1980年代半ばの製品と思われる Star NP-10
    • パラレルポート付きのドットマトリクスプリンターであれば動作する可能性がある
    • 一般的な価格帯は約 80〜120ドル だったが、「動作不明」の表示のおかげで半額ほどで購入
  • 少し清掃し、インクリボンカートリッジを調整した後、テストページの印刷に成功
  • Raspberry PiはWi-Fiに接続し、USBアダプター経由でプリンターのパラレルポートにつなぐ
    • ssh でPiに接続した後、プリンターが /dev/usb/lp0 として認識されていることを確認

プリンターに直接データを送る

  • 最初はシェルから生のテキストを直接送る方法で、印刷できるかどうかを確認
echo "Hello, world!" > /dev/usb/lp0
  • ファイルアクセスエラーが発生したため、権限の問題を chmod で回避
sudo chmod 666 /dev/usb/lp0
  • その後、/dev/usb/lp0 に送ったテキストがプリンターに印字されるようになった
  • PHPでは fopen() でプリンターファイルを開き、テキストを書き込む形に拡張
  • 通常の文章や空白、Unicodeアートを試しながら、プリンターの 文字対応範囲 が限定的であることを確認

Star NP-10の文字セット

  • スキャンされた Star NP-10ユーザーマニュアル を見つけ、プリンターの動作方式を確認
  • このプリンターは非常に限定された 文字セット のみを受け付ける
    • IBM PCの Code Page 437 に緩やかに基づいている
    • 標準的な英数字と一部の特殊記号、罫線、ボックス文字を含む
  • PHPでは16進値を文字列として作り、プリンターへ直接送ることができる
$horizontalDouble = "\xCD";
$deg = "\xF8";

echo str_repeat($horizontalDouble, 24);
echo '78' . $deg . 'F' . PHP_EOL;
  • この方法により、通常テキストだけでなく、罫線、ボックス、温度記号といった 装飾文字 も印字可能

取得するデータとAPI

  • 個人用のフロントページには4つのセクションを入れる
    • 天気
    • 株価
    • 主要ニュース見出し
    • 人気のReddit投稿
  • 実験的なプロジェクトなのでデータ費用を抑え、可能なら無料APIを使いたかったため、無料公開APIを集めた public-apis リポジトリで必要なAPIを探した
  • 使用したデータソースは次のとおり
    • Open-Meteo: 天気データ、APIキー不要
    • twelvedata: 株価データ、余裕のある無料ティアを提供
    • NYTimes: ニュース見出し、プロジェクトに十分な無料ティアを提供
    • Reddit JSON: Reddit投稿、無料だがUser-Agentのスプーフィングが必要
  • PHPスクリプトは各APIエンドポイントからペイロードを取得し、必要なデータだけを大きな配列にまとめる
    • 特定の株式、特定のニュース種別、特定のsubreddit投稿のみを使用
    • セクションのどれか1つでも表示するデータがなければ、スクリプトを早期終了して後で再実行する

ニュースデータのフィルタリング方法

  • NYTimesデータはAPIレスポンスに results がなければ失敗として扱う
  • 記事のうち、次の条件を満たす項目だけを出力対象として集める
    • typeArticle
    • sectionU.S.WorldWeatherArts のいずれか
    • 最大件数 MAXNEWS 未満の場合のみ追加
  • NEWSNEWSKEYMAXNEWS はスクリプト上部で定数として定義し、簡単に変更できるようにしている

紙に合わせた出力フォーマット

  • 単にセクションタイトルを印字するのではなく、上部に現在の日付、曜日、フロントページ名を入れた 枠付きボックス を作る
  • プリンターのページ幅が 80文字 であることを基準にレイアウトを計算
    • 16進文字
    • str_repeat
    • 固定のページ幅値
  • セクションタイトルは罫線文字とテキストを組み合わせて印字
str_repeat($horizontalSingle, 3) . " WEATHER " . str_repeat($horizontalSingle, (PAGEWIDTH - 9)) . "\n";
  • 天気と株価は紙の端に届かない程度に短いため、1行で印字
  • ニュース見出しとReddit投稿は長いテキストが多いため、別途 改行処理 が必要

長いテキストの改行処理

  • プリンターは長い行を自動的に次の行へ続けて印字できる
  • ただし単語が途中で切れて次の行へ送られるのを避けるため、文字列を 最大行長 基準で分割する関数を実装
  • splitString() 関数は空白単位で単語を分け、各行が PAGEWIDTH を超えないよう配列を返す
    • 単一の単語が最大長より長い場合は、その単語を切って処理する
  • Reddit投稿は返された行配列を走査しながらプリンターへ書き込む
foreach (splitString($redditPost) as $line) {
    fwrite($printer, $line) . "\n";
}

自動実行と使用感

  • 手動実行は php print.php で可能
  • 実際の運用はcronジョブで自動化
    • 毎日 午前8時ごろ にパーソナライズされたフロントページが印刷される
    • 印刷した紙を切り離し、コーヒーを飲みながら読む
  • 1枚の紙に収まる有限のニュースは、Webサイトやソーシャルアプリを延々とスクロールする方法より良いと感じられた
  • 古い物理ハードウェアを新しい技術とつないで使う過程そのものも、このプロジェクトの大きな楽しさだった

1件のコメント

 
GN⁺ 2024-10-05
Hacker Newsの意見
  • レシートプリンターで似たようなことをやってみたことがあるが、USBサーマルレシートプリンターは75ドル程度で、Pythonからの制御も簡単
    画像やQRコードの印刷が手軽で、自動カット機能のおかげでメッセージを区切りやすい
    内蔵ベルを鳴らして追加の通知のように使うこともでき、キャッシュドロア制御用の出力もあるので、照明のようなものを制御するのに接続してみようと思っている
    メール用に設定してあり、毎朝スケジュール表を印刷するようにしていた
    ボタンやNFCリーダーのような物理的な操作系と一緒に使うと、インターフェースとしてかなり相性がいい。たとえばスケジュール表印刷用のNFCカード、未読メール印刷用のNFCカードのように、「コマンド」を出して印刷を受け取る形
    スクリーンタイムを減らす面白い方法だが、皮肉なことに、節約できた時間よりもこれをコーディングして設定するために画面を見ていた時間のほうが長かった気がする

    • レシートプリンターは楽しいが、有害な感熱紙を買わないように注意したほうがいい
      https://www.consumerreports.org/cro/news/2014/03/the-health-...
    • うちの感熱式プリンターも毎朝天気を印刷し、重要な機器がネットワークから外れると通知を印刷する
    • レシートプリンターは本当に楽しい。数年前に似たような構成でGitHubチケットを印刷するプロジェクトをやったことがあり、今ドットマトリクスプリンターで使っている構成と似ていた
    • どのプリンターを使っているのか気になる。1台買おうかと思っていたところで、言っていた通知機能や外部制御機能は知らなかった
  • 今日ふと思った
    この人がやっていることのひとつは、単に /dev/lp0 に echo しているだけなのだが、昔は本当にそういうものだった。インターフェースにテキストを流し込めばプリンターが印刷していた
    今どきのプリンターはずっと華やかだが、長い歴史を持つプリンターであることに変わりはない。初期のHPレーザープリンターでも、データを回線に送れば Courier 10、1ページ66行で印刷された。Apple LaserWriterだけは専用のPostScriptプリンターだったのでそうではなかった気がするが、その代わりPostScriptを流し込んでいた
    プリンターが進化するにつれて送る言語は複雑になったが、それでも長い下位互換性は保たれていた
    ではUSBプリンターをコンピューターにつないで ls > /dev/usbXXX をやると、今でも印刷されるのだろうか。まだ普通に動くのだろうか?
    EPSONにEPSON MX-80エスケープコードを送ったら今でも通るのだろうか。どちらでも驚かないが、最近のプリンターは自分にはかなりブラックボックスなので、知っている人がいるのか気になる
    昔、あらかじめ印刷済みの多枚複写NCR用紙にレポートがぴったり収まるよう悪戦苦闘していた楽しさを覚えている人もいるかもしれない

    • OS Xで今試してみたが、説明されていたように /dev/ 以下へプリンターを露出はしていないようだ。その代わりOS Xにも lp があるので、echo "Hello printer" | lp -d のように使え、名前は lpstat -p で見つけられる
      新しいプリンターで試したところ、実際に動いた
    • 下の2つはどちらも自分の環境で動いた
      printf 'hello\f' > /dev/usb/lp0
      printf 'hello\f' | nc -N $printer_ip 9100
      Brotherのレーザープリンターでの話で、オンライン説明書の横にプログラミングガイドへのリンクがある。言語はPCLだが、簡単な印刷ならそこまで多くを知る必要はない
      上の2つはCUPSを使っていない。他のコメントにあるように lp / lpr 実行ファイルを使うなら、まずプリンターをCUPSに登録しておく必要がある
      ls > の場合、プリンターはDOSの改行を期待している。\n は改行するだけで「キャリッジリターン」しないので、sed 's/$/\r/' にパイプするか nc -C を使う必要がある
      USB接続では何度か出力して1ページを作ることができ、フォームフィードを送るまでは紙は出てこない。TCP接続では接続が閉じられた時点でページが印刷される
    • 数年前に新品で買ったEpson LX-350があるが、USB接続でき、シリアル/パラレルポートもある。USBでつなぐと /dev/usblp0 のような形で現れ、ただ cat で送るだけでも動いた
      こういう製品を新たに買う顧客は、過去30〜50年使ってきたプロセスとの互換性を望むはずなので、予想どおりESC/P 2をサポートし、IBMのエスケープコードにも対応している。90年代に使っていた古いマトリクスプリンターはIBMコードには対応していなかった気がするので、そこは意外だった
      さらに驚いたのは、MacBookに汎用Epsonプリンター向けの内蔵ドライバーがあり、しかも動いたことだ。品質は今ひとつで、グラフィックとして印刷していたが、とにかく存在していた
      最新のインクジェットやレーザープリンターについてはよく分からない。20年ほど前に使っていたEpsonのインクジェットは生のESC/Pコードをサポートしていた
    • ネットワークプリンターでも可能。開いているポートにnetcatでPDFを送れば印刷される
      https://retrohacker.substack.com/p/bye-cups-printing-with-ne...
    • 1990年代の学校のコンピューター室には、まだドットマトリクスプリンターがあり、ネットワーク上のすべてのコンピューターでデフォルトプリンターに設定されていた
      よくあるユーザーのミスのひとつは、誰かがWord文書を印刷しようとしてPostScriptがドットマトリクスプリンターに送られ、プリンターがそれをPostScriptソースそのまま忠実に印刷してしまい、誰かが止めるまで紙とリボンを無駄にし続けることだった
  • マトリクスプリンターも、機種によってはかなりいろいろなことができる。フォント変更、太字、下線、ときにはイタリック、倍幅/倍高文字、グラフィックスまで可能。ただしグラフィックスはたいてい 90 または 180 DPI のような比較的低解像度。
    以前、脱出ゲームのようなもののために、パラレルプリンターコネクタしか付いていない箱を作ったことがある。プリンターにつなぐと、パラレルポートの制御線の1本から 寄生電源 を取り、超小型の PIC マイクロコントローラが数百 µA しか使わずにヒントをプリンターへ送っていた

    • 昔、初期のデスクトップ出版ソフトの1つに SoftCraft の Fancy Font というものがあった。CP/M、のちには DOS のプログラムで、PageMaker のような WYSIWYG のページレイアウトツールではなく、簡単なマークアップ言語で書式指定したテキスト文書を使っていた。
      当初は Epson ドットマトリクスプリンターの高解像度グラフィックモードを活用していた。これらのプリンターは、プリントヘッドのピン間隔の 1/3 だけ細かくプラテンを微調整できたので、ヘッドだけで可能な垂直解像度の 3 倍を出せた。
      Fancy Font はコンピュータ上でテキストをレンダリングしてから、この特殊な高解像度モードのグラフィックスとして送り、1980年代初頭の家庭用機材としては可能な限り組版に近い結果を作り出していた。
      後のバージョンでは、初代 HP LaserJet のような初期レーザープリンター向けのドライバーも備えていたが、Mac が登場すると、その手のシステムの先行きは明らかだった
    • 父は90年代に 4色ドットマトリクスプリンター を持っていた。Deluxe Paint II のファラオの頭を印刷するのにはものすごく時間がかかったが、実際かなりきれいだった。
      ただ、印刷後は紙がひどく反っていた。プリンター自体はまだ持っているけれど、4色リボンをどこで手に入れられるのかは分からない
    • 連続ロール紙に横向きで巨大なバナーを印刷していたのを覚えている。今のターミナルで figlet のようなコマンドが作る ASCIIアート に似たものだった。もしかすると今でもプリンター出力をサポートしているかもしれない
    • デザインの観点から、これをもっと掘り下げてみたかった。マニュアルにはフォントサイズ、強調、イタリック、下付き/上付き文字などについてのページが本当に何十ページもある。
      たぶんバージョン 2.0 で試すかもしれない
    • ESC/P を理解して、複数のフォントや CPI などをサポートするターミナルがあったら面白そう
  • この機械を数年間ニュースフィードにつないでいた。[1] Model 14 Teletype テーププリンター の機構で、今も居間にあり、テープはワイヤーバスケットの中へ流れ出てくる。
    古い EeePC サブノートで動かしている Python プログラムで駆動している。
    [1] https://aetherltd.com/refurbishing14.html

    • 本当にかっこいい。更新され続ける株価や暗号資産価格を打ち出す ティッカーテープ を真似するために、こういう機材をぜひ一度手に入れてみたいと思っていた。
      EeePC という名前を聞くのも本当に久しぶりで、懐かしくなった
  • 本当に素晴らしい製品アイデアに見える。毎朝、MSN みたいなものではなく、本当に自分で選んだオフスクリーンのニュースフィード を受け取るという発想がいい。
    しかも目覚まし時計まで ドットマトリクスプリンターで置き換え られるなら、なおさらいい。
    PHP を自分のニュースソース向けに直すのは簡単にできそうだが、ハードウェア側を一人でどう始めればいいのかは分からない。こういう人はかなり多い気がする。
    市販されたら、古いプリンターの値段よりずっと高くても買うと思う

    • 以前に似たことをやった者として言うと、実際かなり簡単。プリンターをつないで、dev 出力に書き込むだけでいい。Linux で動かす前提なら、その出力は単なるファイル。
      一番難しいのはプリンター接続で、変換ケーブル が必要になるかもしれない
  • いいね。昔少しだけラジオ局で働いていたときのことを思い出した。細かいところはほとんど忘れたけれど、ある Associated Press の番号 に自動でダイヤルして最新の見出しを取得し、それをドットマトリクスプリンターに送っていた気がする。
    90年代後半のことで、MS-DOS 上で動いていた。
    当時のほとんどのプリンターは制御コードでフォントを設定できたし、多くのプリンターには 可変幅フォント もあった

  • いいと思う。最近、FT Weekend のような 週末の紙の新聞 を取ろうかと考えている。スマホでニュースをあまりにも頻繁に読んでしまうから。
    ニュースはあまり役に立たないのに、ネガティブな感情ばかり生むことが多い。紙で、それも週1回だけニュースを見るほうが落ち着けそうだ。
    毎日紙にニュースを印刷するこのやり方は、その中間を埋めるのに良さそうに見える。
    ついでに言うと、ドットマトリクスプリンターが本当に好きだ。こういうふうにハックしやすい オープンソースプリンター はあるのだろうか?

    • FT は勧めにくい。
      紙の新聞を受け取ろうとしたが一度も届かず、電話を3回、メールを10通ほど送ったあと、解約と返金を求めてようやくチケットをエスカレーションすると言われた。その時点でもう3週間たっていて、こちらの時間もかなり使っていた。
      なので、画面を見続けないためにインターネットのニュースを自分で印刷することにもとても興味がある
  • しばらくの間、三面カード を印刷していた。片面には画像があり、もう片面には文書につながる QR コードがある。
    https://mastodon.social/@UP8/111013706271196029
    「三つ目」の面は、その QR コードがリンクしているウェブサイト。
    写真に飽きてしまったので、安いレンズを持ち歩き、絞りを常に f/18 以上にして、強い後処理と色補正をかけ、標準的ではあるが非標準に感じられるアスペクト比で撮るというキャラクターを作り出した。まるで別の時間線にある奇妙なカメラを使っているように見せたい、という設定。
    このシリーズを印刷し始めてから、4x6 を切れば 4x5 を簡単に作れるという結論に達したが、切る代わりに 1 インチ分の余白を残して、表面に QR コードと文書を入れられるとも考えた。同様に、5x7 を 5x5 の正方形に切れば文書を入れる余地ができる。
    裏面に印刷できない光沢紙が何箱かあるので、そういう使い方をしようと思っている。あとで Instagram に 4x5 規格があることや、良いレンズで撮ったスポーツ写真がその形式だと本当に映えることも知った。
    ただ、文書の見た目をどうするかで迷っている。今の構成を最小限だけ変えるやり方、その架空のカメラに内蔵されていそうな古いプリンター風の フェイクのドットマトリクス効果、あるいはインクジェットプリンターの利点を最大限に生かすやり方の間で揺れている

    • 理解したいのだけれど、文章そのものか、あるいは自分がかなり多くの文脈を取りこぼしている気がする。ほとんどすべての段落が前の段落とまったく無関係に見える
  • 「実験プロジェクトなので、このデータ費用をとても安く、できれば無料で維持したかった」というなら、NewsCatcherもある。オープンソースのサイドプロジェクトなら無料
    https://docs.google.com/forms/d/e/1FAIpQLSejrsj4a1ZQkIasiKCt...

  • 少し関連する話として、毎朝 MacBook で NYTimes 1面 を開く小さなスクリプトを使っている
    d=$(date +%d)
    m=$(date +%m)
    y=$(date +%Y)
    wget -q [https://static01.nyt.com/images/$y/$m/$d/nytfrontpage/scan.p...](<https://static01.nyt.com/images/$y/$m/$d/nytfrontpage/scan.pdf>;) && open ./scan.pdf