non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

Raspberry Piの温度をgRPCを使ってElectronで作ったデスクトップマスコットに表示させた

おはようございます。長男は自分に似て忘れ物多く、先日奥さんが学校に一緒に宿題のノートを忘れて下校後にとりに行った際、机の中からなくなってしまった数々の アイテムが発見されるなど順調なw小学校生活となってきました。@kjunichiです。

背景

こどもたちにRaspberry Piを占有(おもにRaspberry Pi版のマインクラフト)されがちで、リモートからアクセスすることが多くなった。 どんどん暑くなる季節。これまでの記事にもあるように、Raspberry Pi3は温度が高くなりがち そんな中、Raspberry PiのCPUの温度が気になる。

デスクトップマスコットのgopheronにRaspberry Piの温度をしゃべらせよう

黒い画面も味気ないので、ふとデスクトップマスコットのGopheronの機能追加も兼ねて gRPCの勉強がてら取り組んでみようという流れに。

Node.jsのgRPCは静的な実装も選べるが、動的だとprotoファイルのコンパイル的な物が不要

システム構成図のようなもの

すでにWebSocketというかSocket.ioで通信しているが、今回はgRPCを使う事も目的の一つなので、 Raspberry Piとの通信はgRPCで実装を進めた。

以下の様なイメージ

f:id:kjw_junichi:20180505092200j:plain

工夫したところなど

もともと、Gopheronでは Gopher君のセリフをCanvasに描画してそれをThree.jsでテクスチャとして ポリゴンに表示するという大変回りくどい実装を行っていた。

今回はさらにこれに悪ノリして、絵文字や、セリフの文字を多くしたかったので、既存のセリフを直接Canvasに フォント描画するところを、HTMLをレンダリングしてSVGを経由してCanvasイメージにするという 実装を行い、本人としてはいい感じになったし、客観的にもインスタ映えしたので、海外から非常に高い評価を 頂いた。

gRPCまわり

公式のHelloworldをそのまま流用して、PCからサブコマンドを受け取り、Raspberry Pi側でそれを実行し、 実行結果を返すというとてもシンプルな実装。関数名もそのまま流用というw。

Raspberry Pi

func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    out, err := exec.Command("vcgencmd", in.Name).Output()
    if err != nil {
        log.Fatalf("Exec fail: %v", err)
    }
    return &pb.HelloReply{Message: string(out)}, nil
}

クライアント側(PC)

const client = new hello_proto.Greeter('raspberrypi.local:50051',
    grpc.credentials.createInsecure())
  client.sayHelloAgain({
    name: argv
  }, (err, response) => {
    //console.log('Greeting:', response.message)
    const tmp = response.message
    const msg = `${tmp}<span style="font-size:larger;font-family: 'Segoe UI Emoji';">${getEmoji(tmp)}</span>`
    const html = `<div style="display: flex;flex-wrap:no-wrap;"><div style="width: 132px;padding-right: 2px"><img src="${icon}"></div><div style="font-size: 27px;wrap">${msg}</div></div>`

    socket.emit('gopher sendHtml', html)
  })

response受け取り後の文字列編集こそ、ごちゃごちゃしているが、基本公式のHelloWorldと同様。

成果物

github.com

github.com

使い方

Go言語が動く状態のRaspberry Piであれば、以下の様にgRPCサーバーを動かす

go get -u github.com/kjunichi/gopheron-raspberrypi
cd $GOPATH/src/github.com/kjunichi/gopheron-raspberrypi
go run server/main.go

Go言語が入っていないRaspberry Piの場合、Go言語が動くPCでクロスコンパイル可能です。

go get -u github.com/kjunichi/gopheron-raspberrypi
cd $GOPATH/src/github.com/kjunichi/gopheron-raspberrypi
GOOS=linux GOARCH=arm go build server/main.go

作成されたバイナリ(main)を

scp main pi@raspberrypi.local:/home/pi/

などでRaspberry piに配置して、これを実行します。

子供たちに占領されていないPC側でGopheronを動かし、おもむろに以下を実行

go get -u github.com/kjunichi/gopheron
cd $GOPATH/src/github.com/kjunichi/gopheron
npm install
go build gopheron.go
./gopheron
node rpiClient.js measure_temp

実行結果

f:id:kjw_junichi:20180616073825g:plain

学べたこと

goでもcgoを使うとクロスビルドで依存ライブラリを用意したり大変になる。 ピュアGoだとこの心配が不要ということも今回の作業で分かった。

そして、クロスコンパイルしてRaspberry Piで動いたことで、 gRPCがピュアGo実装だったのだと実感した。

Node.jsのgRPCだと定義ファイルを変更してもビルド不要で動かせる 動的モード?があるので、便利だった。

参考資料

grpc.io

qiita.com

関連記事

14年前の記事

4年前の記事