もぐてっく

人は1つ歳をとるたび、1ビットづつ大きくなれると信じてた。

Pirate Audioの前面ボタンを/dev/input/eventXなキーボードとして使うソフトを作ってみた

サマリー

f:id:moguno:20201227155857j:plain:w400

  • Raspberry Pi用のコンパクトな液晶 & スピーカー & ボタンHATのPirate Audio Speaker for Raspberry Piがすごく良い。
  • そのボタンを/dev/input/eventXなキーボードにするプログラムを書いた。

Raspberry Piの弱点を完全にカバーしてくれるときめきデバイスをゲット

前から思ってたんです。ラズパイってヒューマンインタフェースが弱いなって。

ヒューマンインタフェースと言うのは、人間とコンピュータが対話するための入出力の手段のこと。
モニタやスピーカーのような人間の五感に訴える出力手段とか、キーボードとかタッチセンサーみたいな人間の意志をコンピュータに伝える入力の手段すね。

ラズパイのデフォルトだとそれがほぼないんですよね。

  • 出力する手段:一応アクセスランプのちっちゃなLEDを制御可能
  • 入力する手段:なし

まぁそのための拡張用40Pinなんですが、ジャンパ線がぴょんぴょんしてる基板をライフをハックするデバイスとして日常的に使えるかと言うと厳しいところがあると言うのが個人的な見解です。

(なおもぐのさん。はんだ付けがとても苦手なのは秘密です。)

そんなことを思いながら生きてたところ、公式サイトにときめくプロダクトが。

革命的だぜPirate Audio Speaker for Raspberry Pi

それは、Pirate Audio Speakerと言うHAT基板。
ラズパイW Zeroサイズの基盤にちっちゃい液晶、モノラルスピーカー、小さな4つのボタンが搭載されてます。

f:id:moguno:20210105181648j:plain:w200

もともとはラズパイを高音質なオーディオプレーヤーにするためのプロダクトなんですが、見事に上記のヒューマンインタフェース問題を解決してくれるHATになってます。

有志による解析も進んでて、独自のプログラムからでも使える感じになってます。

  • 液晶:ごにょればフレームバッファとして使用可。コンソールもXも使えるぜ!(すごいぜ@akkiesoftさん)
  • スピーカー:もともとALSA経由で使用可
  • ボタン:もともとGPIO経由で読み込み可

しかしながら、ボタンがGPIOなのがちょっと残念ポイント。
これがキーボードになれば、dialogコマンドとシェルスクリプトで超簡単に対話型のアプリが作れるのに・・・。

と言うわけで前面ボタンをキーボードに見せかけるアプリを作ってみました!

github.com

使い方

準備

Raspberry PiのGPIOを制御するwiringpiをインストールしてください。

sudo apt-get install wiringpi

コマンドライン引数

./pirate_audio_buttons Aボタンのキーイベントコード Bボタンの〃 Xボタンの〃 Yボタンの〃

イベントコードは以下を参照。キーボードのCキーを模擬するならKEY_Cに対応する46を指定します。

linux/input-event-codes.h at master · torvalds/linux · GitHub

0を指定するとそのボタンは無効になります。

起動方法

&を付けてバックグラウンド起動してください。
Bボタンを"yキー"、Yボタンを"nキー"にする場合はこんな感じ。

./pirate_audio_buttons 0 21 0 49 &
PID=$!

例えば、コンソールでdialogコマンドを実行してBボタン or Yボタンを押すと結果が得られると思います。

openvt -f -c 1 -- sh -c 'dialog --ascii-lines --yesno test 0 0; echo $?'


f:id:moguno:20210105195008j:plain:w400

終了方法

killしてください(爽やかな笑顔)

kill $PID

参考

Pirent Audioの液晶をコンソールとして使う方法

akkiesoft.hatenablog.jp

妻に尻にしかれ娘にスネをかじられてる僕が、いかにして自由に遊べるおうちネットワークを構築したかの記録

自宅ネットワーク。それは、

始めの方は楽しい!楽しい!と構築するんだけども、一旦安定動作し出すとすっかり構成を忘れちゃうもの。
完全に忘れちゃう前にメモっといた方がいいなと。

そう言えば仕事でもネットワーク構成図ってあんまり書かないな。
と思って、一度習作してみたくなったのもあります。

大公開!もぐの家のネットワーク構成!

f:id:moguno:20201230164812p:plain

コンセプト

このネットワーク構成に至ったコンセプトは以下です。

表テーマ:家族に迷惑をかけない!

自宅でネットワーク遊びをするならDHCPとかDNSとかもサーバに
OSSを入れて色々変な運用をしたいですよね。

でも、もしもサーバが不慮の事故で止まったりしたら・・・。

怒ると怖い嫁さんと五月蠅い長女のスマホゲーやAmazonプライムDoS状態に。

結果、即もぐのの家庭内カーストの順位が急降下することになります。
(多分、前に長女が捕まえてきたバッタといい勝負になると思います。嘘だといってよガンディー。)

と言うわけで、家族用のネットワークの信頼性は僕の人間らしさのための至上命題でした。

これに対するソリューションとして、タグVLANを使ってL2のセグメントを家族用(タグなし)ともぐの実験用(タグ1)に分ける構成にしました。

な感じです。

この構成。仮に実験ネットが崩壊しても家族用ネットから容易にインターネットが利用出来るのもメリットですね。

裏テーマ:家族ネット→「ぐびっ!(リビドーの擬音)」ネットの完全なる分離

このネットワークには、家族ネット→実験ネットのL3的な経路は設けていません。

最大の理由はDHCPを提供しているONUがスタティックルートを設定できないってとこなのですが、副作用的に家族がもぐのネットの各種ノードに偶然/意図的にアクセスすることができない構成になっています。

男の子なら誰でも家族に見られたくないものってあるよね。

もぐの家ネットの主要な機器に迫る!

ONU・宅内スイッチ

ONUと宅内スイッチは情報ボックスに入ってます。
そう言えば情報ボックスって開けたことないなぁ。ONU設置は僕の留守に業者がやってくれたし。

いい機会だし、スイッチの型番とか確認しよっと。ガチャ。

f:id:moguno:20201230150637j:plain
(ぐちゃあ)

パタン(そっ閉じ)

無線アクセスポイント(NETGEAR WAC505)

f:id:moguno:20201230172222j:plain

比較的低価格な業務用アクセスポイントです。
こいつの特徴はSSIDごとにVLANを切れるところ。
これで子守をしながらでもWifi経由で実験用ネットに入ることができます。

デメリットは故障時に替えの機器が容易に確保できないところです。
これは家庭内ネットをタグなしにすることで、市販のWifiルータを繋げば家庭内ネットだけは復旧できるようにしています。

今見たら後継機になってました。ルータモードもあるらしくいい感じです。

PoE対応スイッチ(NETGEAR GS308P)

f:id:moguno:20201230172525j:plain

前述のWAC505の電源供給手段がPoEのみなので一緒に購入。
LANケーブル一本でアクセスポイントを取りまわせるのはなかなか快適です。

VLAN間ルータ(EdgeRouter ER-X)

f:id:moguno:20201230172557j:plain

もぐの実験ネット→インターネットへのゲートウェイ君。

ソフトウェアルータってどうしてもパフォーマンスが下がっちゃうので、昔買ったEdgeRouterを置いてIPマスカレードさせてます。

これに搭載されているEdgeOSはLinuxベースのソフトウェアルータVyatta(現VyOS)をフォークしたもので、コマンド体系が一緒なのが素敵です。さらにGUIが結構優秀。

f:id:moguno:20201230180015p:plain

さらに言うとJuniperのファイアウォールに搭載されてるJunOSともコマンド体系が一緒なので、お仕事のお勉強にも使えたりします。

こだわりポイントはタグ1とタグなしのポートを分けてLANケーブル2本で接続しているところ。
これでインターネットの下りが20Mbps→150Mbpsくらい速くなります。

ケーブル1本だとタグ違いの同一データが同じLANケーブルを往復することになるので、それがパフォーマンス低下に繋がっているぽいです。多分。

実験用クラウド(Proxmox VE)

実験用クラウドにはProxmox VEのコミュニティサブスクリプションを採用しています。

Proxmox VE

f:id:moguno:20201230173947p:plain

定番のVMWare ESXiと比べた時のメリットは以下。

  • Debianベースなので使えるLANカードとかの制約が少ない。
  • 要求スペックが低い(最低メモリ1GB)
  • コンテナ(LXC)ベースの軽い仮想環境が作れる

サーバーアプリケーションの実験で一時的にVMを作ったりとかマイクラサーバーとか。
後ぐびっ!なファイルサーバなんかがいます。

家族向けファイルサーバ

f:id:moguno:20201230172416j:plain

UbuntuにSambaを突っ込んだファイルサーバです。

ハードウェアは以前とあるブロガーさんの記事をツイートしたらそれがバズって、その感謝の印としていただいたNUCです。その節はありがとうございました。

kannnonn.com

置いてるのは家族の写真で、EXIFを参照して自動でファルダ分けが行われるようになってます。

さらに、週一でOffice365のOneDriveに自動バックアップをするようにしています。rclone便利です。

これでマシンが壊れようが家が火事になろうが、娘たちの結婚式スライド用の写真は生き残れるという算段です。

ちなみに、1TBのオンラインストレージではOffice365が一番安いはずです。お勧めです。

最後に

あんまりなんもしてないつもりでしたが、意外と語りたい要素がありました。ど長文。
 
後これ、明日大掃除せんとあかんすね。。埃だらけだ。

来年の目標はDockerのコンテナを動かせるノードをどっかに置きたいですね。

Spring FrameworkでHUGっと!プリキュアを実装する

新春なのでSpring Frameworkの話

協力会社さん
「もぐのさん、今度のJavaの案件。Spring Bootを使ってもいいですか?DB処理とかサーブレットとか簡単にできるんで。」



「ああー?何それ?開発効率いいの?そう?まぁええんちゃう!うぇーい!」

(2か月後)

協力会社さん
「できました!」



「おぅ…いいね!エモいね!ひゅー!!(え…読めない…何この@Autowiredって…)」

って事件が2019に発生。
そこから一年。


Spring Bootぱねぇ!ってかSpring Frameworkがすごい!mikutter並みにすごい!!


Hey! Everyone!Say!Spring!Spring!Foo!

すっかりSpringに洗脳された自分がいました。

もうこれは布教していかないと人類の損失ではないか!
そうだ!ブログを書こう!年末年始暇だし!!!

と、言う経緯で筆を取った次第です。


さて、皆さんにご説明するにあたり、なんか手頃なモデルが必要です。
抽象クラスが作れる程度の共通項がある何かで、インスタンスがいっぱい作れる奴・・・


あっ!プリキュアだ!


と言うわけで、今回はプリキュアを題材にしてSpringのすばらしさをお伝えできればと思います。

プリキュアとはなんだ?(哲学)

とは言ったものの、プリキュアってよく知らないんですよね。僕おジャ魔女世代なので。

しかしながら変身シーンとかはなんとなく印象に残ってて、

  • みんなで変身キーワードを叫ぶ
  • 画面が4分割か5分割になって各々の変身シーンが流れる。
  • 変身が終わったら一人一人にスポットが当たって、一言口上と変身後の名前を名乗る。(みんなのミラクル!キュアみらくるん!みたいな)

って感じだったかと。

この辺をモデル化してみましょうか。

package net.moguno.precure;

public abstract class プリキュア {
    protected String チーム名;

    protected String 変身前の名前;

    protected String 変身後の名前;

    protected String 変身キーワード;

    protected String 名乗り;

    public String getチーム名() {
        return this.チーム名;
    }

    public String get変身前の名前() {
        return this.変身前の名前;
    }

    public String get変身後の名前() {
        return this.変身後の名前;
    }

    public String get変身キーワード() {
        return this.変身キーワード;
    }

    public String get名乗り() {
        return this.名乗り;
    }
}

こんな感じすかね。

さて、モデルができたので次は具体的なプリキュアを実装します。

とは言っても特に当てもないので、このサイトからもぐのの好みの子を選ぶことにしました。

www.animatetimes.com

数時間の熟考の末、勝ち残ったのはキュアエールちゃんでした!
チアのポンポンを振り回して戦うみたいです。可愛いです。

www.toei-anim.co.jp

このシリーズは元々3人から始まって、後から双子が加入して5人で戦うお話らしいです。

変身のキーワードは全員共通で「ミライクリスタル!ハートキラっと!」

これはベースクラスを作ってそこに実装した方がいいですね。

と言うわけで「HUGっとプリキュア」クラスと「キュアエール」クラスを作ってみることにします。

package net.moguno.precure;

public class HUGっとプリキュア extends プリキュア {
    public HUGっとプリキュア() {
        this.チーム名 = "HUGっとプリキュア";
        this.変身キーワード = "ミライクリスタル!ハートキラッと!";
    }
}

 

package net.moguno.precure;

import org.springframework.stereotype.Component;

@Component ←←←←←ポイント
public class キュアエール extends HUGっとプリキュア {
    public キュアエール() {
        this.変身前の名前 = "野乃はな";
        this.変身後の名前 = "キュアエール";
        this.名乗り = "輝く未来を抱きしめて!みんなを応援!元気のプリキュア!キュアエール!";
    }
}

ここでのポイントは、クラスに@Componentアノテーションを付けておくことです。
こうしておくと別のクラスで@Componentクラスのフィールドを@Autowired付きで宣言したときに、実行時にSpringが勝手にシングルトンを作って代入しておいてくれます。

@component
public class 例 {
    @Autowired
    protected キュアエール エールちゃん; ←←←←←← 実行時にキュアエールのインスタンス(シングルトン)が代入される
}

いちいちnewする手間を省く便利な機能です。ここではね。ふふふ。

続いて、メイン処理になる変身シーンを実装していきます。
メイン処理はSpring Webを使ってWeb APIにしてみます。

package net.moguno.precure.restcontroller;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import net.moguno.precure.プリキュア;

@RestController
public class 変身シーンAPI {
 @Autowired
 protected List<プリキュア> プリキュアたち;

 @GetMapping("/metamorphose")
 public String 変身シーン() {
  StringBuilder セリフ = new StringBuilder();

  Map<String, List<プリキュア>> チーム別 = 
   this.プリキュアたち.stream()
    .collect(Collectors.groupingBy(プリキュア::getチーム名));

  for (List<プリキュア> チームメイトたち : チーム別.values()) {
   String 変身前の名前 = チームメイトたち.stream()
    .map(プリキュア::get変身前の名前).collect(Collectors.joining("、"));

   セリフ.append(String.format("%s「%s」<br>", 変身前の名前,
    チームメイトたち.get(0).get変身キーワード()));
  }

  セリフ.append("<br>");

  this.プリキュアたち.stream().map(メンバー -> 
   String.format("%s「%s」<br>", メンバー.get変身後の名前(),
   メンバー.get名乗り()))
    .forEach(変身後のセリフ -> セリフ.append(変身後のセリフ));

  return セリフ.toString();
 }
}

サーブレットの煩わしいお決まり処理をアノテーション一つで解決できちゃうのがSpring Bootのいいところですね。

さて、作ったAPIWebブラウザでたたくと、こんな感じでキュアエールちゃんが変身します。

f:id:moguno:20201226202547p:plain

まだ一人分しかクラスを作ってないので寂しいですね。
まだ仲間が加入する前の第1話ってところでしょうか。

このプログラムを第5話「宙を舞え!フレフレ!キュアエトワール!」に改造する。

HUGっとプリキュアのあらすじを見ると、第2話でキュアアンジュ(青)、第5話でキュアエトワール(黄色)が加入するようです。

www.toei-anim.co.jp
www.toei-anim.co.jp

では、2人のクラスを定義して第5話の変身シーンを再現してみましょう。

package net.moguno.precure;

import org.springframework.stereotype.Component;

@Component
public class キュアアンジュ extends HUGっとプリキュア {
    public キュアアンジュ() {
        this.変身前の名前 = "薬師寺さあや";
        this.変身後の名前 = "キュアアンジュ";
        this.名乗り = "みんなを癒す!知恵のプリキュア!キュアアンジュ!";
    }
}

 

package net.moguno.precure;

import org.springframework.stereotype.Component;

@Component
public class キュアエトワール extends HUGっとプリキュア {
    public キュアエトワール() {
        this.変身前の名前 = "輝木ほまれ";
        this.変身後の名前 = "キュアエトワール";
        this.名乗り = "みんな輝け!力のプリキュア!キュアエトワール!";
    }
}

今回の改造個所はこの2人分のプリキュアクラスの追加のみ。
メイン処理には手を付けていません。

なぜなら、List<プリキュア>なフィールドに@Autowiredを付けると、クラスパスにあるプリキュアの派生クラスをすべて探してインスタンス化してくれるんです!!

なので、メイン処理をポリモフィズムやインターフェースを使った抽象化前提の設計にしておけば、後はクラスを足すだけでどんどんアプリを拡張していけるんです!

これがこのブログで伝えたいポイントです!(お前ここまで何文字使ったよ)

論より証拠と言うことで実行結果がこちら。
ちゃんとみんなで叫んで、個人が順番に口上を述べてますね。

f:id:moguno:20201226202349p:plain

Springの@Autowired機構の実力はこんなもんじゃありません。
もっとすごいことができるんです。
さぁ次に行くのです!

さらにこれを第22話「ふたりの愛の歌!届け!ツインラブギター!」に改造する。

あらすじを読み進めてみると、なんと第22話で初代「ふたりはプリキュア」のキュアブラックキュアホワイトがゲストで登場するらしいです。過去作参戦は熱いですね!

www.toei-anim.co.jp

ここではシリーズ間の壁をjarファイルで表現して、Springのヤバさを体感してもらおうと思います。

ふたりはプリキュア.jarにキュアブラック・ホワイトを定義して、それを今まで作って来たHUGっとプリキュア.warの世界に呼んで来ようという企画です。

まずは、HUGっとプリキュアと同じ要領で「ふたりはプリキュア」クラスと「キュアブラック」、「キュアホワイト」クラスを作ります。

package net.moguno.precure;

public class ふたりはプリキュア extends プリキュア {
    public ふたりはプリキュア() {
        this.チーム名 = "ふたりはプリキュア";
        this.変身キーワード = "デュアルオーロラウェーブ!";
    }
}

  

package net.moguno.precure;

import org.springframework.stereotype.Component;

@Component
public class キュアブラック extends ふたりはプリキュア {
    public キュアブラック() {
        this.変身前の名前 = "美墨なぎさ";
        this.変身後の名前 = "キュアブラック";
        this.名乗り = "光の使者!キュアブラック!";
    }
}

 

package net.moguno.precure;

import org.springframework.stereotype.Component;

@Component
public class キュアホワイト extends ふたりはプリキュア {
    public キュアホワイト() {
        this.変身前の名前 = "雪城ほのか";
        this.変身後の名前 = "キュアホワイト";
        this.名乗り = "光の使者!キュアホワイト!";
    }
}

あとは、HUGっとプリキュア.warのcontext.xmlに、ふたりはプリキュア.jarを読みこむように設定すれば準備完了です。

<Context>
  <Resources>
    <PostResources base="C:\Users\mogun\ふたりはプリキュア.jar"
                   className="org.apache.catalina.webresources.JarResourceSet"
                   webAppMount="/WEB-INF/classes"/>
  </Resources>
</Context>

実行結果はこちら。

f:id:moguno:20201226203301p:plain

HUGっとプリキュアキュアブラックキュアホワイトとの夢の共闘が実現です!
(別途キュアマシェリとキュアアムールも実装してます。)

・・・って胸を熱くするのはそこではなくて。

Springの@Componentと@Autowiredを使えば、もはや本体のwarをいじることなく機能拡張が出来てしまいます。
これはもうプラグイン機構と言っても差支えがないのではないでしょうか。

これをSpring Bootと組み合わせると、さっきWebAPIを作るときに使った@RestControllerを別jarに置いて、プラグインでWebAPIを後から生やすことも可能です。
逆に本体の@Repositoryを@AutowiredしてプラグインからDBアクセスをしたりもできます。

自由です。ヤバいです。楽しいです!!Fuuuuuuu!!!

鬼長文になりましたがすこしでも伝わりましたでしょうか。Springのすごさ。

最後に、これを作ってて作りたくなったのを作って終わりにします。

プリキュア!レリーズ!シャイニングメモリー

f:id:moguno:20201226202723p:plain

いや~オールスターズメモリーズ最高すね!!

敵キャラのミデンがほかのプリキュア映画には無いリアルな闇を抱えてて、それに対するエールの包み込むような優しさがもうね!

前半の「こんなの!私のなりたい野乃はなじゃない!」most感動ポイント!挿入歌もポイント高い。

後半の歴代テーマソングのメドレーも感慨深いものがありますね。何百回も聴きましたよほんと!

アマゾンプライムにあるのでみんなも今すぐ見よう!