Ruby
RaspberryPi
dashbord

Raspberry Piで作るお手軽Dashbord

More than 1 year has passed since last update.

こんにちは。Livesense - 関 Advent Calendar 2017の9日目を担当しますエンジニアの@kurobaraです。

リブセンスでは、就活生向けのメディアである就活会議の開発をしています。

今年の半ばまでは、会社の口コミサイトである転職会議のメディアチームに所属してAWS周りのことを主にやってました。

昨年は・・・


Raspberry PiにFedoraをインストールという、少し気が狂ったとしか思えなかったことをしていました(笑)

今年は昨年インストールしたFedora入りRaspberry Piが今現在、どういう運用になっているかを書こうと思います

中々、皆さんこってりしたことを書かれているので、箸休め的になればなぁ〜と思います( ̄ー ̄)bグッ!

内容としては、 テーマが関なだけにKPIのダッシュボードに関係ありそうな内容として書こうと思います。

最初に結論


想像に難しくないのですが、Fedora辞めてraspbianに泣く泣く戻しました(笑)
だいたいこのあたりがネックでした(´・ω・`)

  • 動作が遅い
    • ssh越しにすると目も当てられない
    • というか、動作が重すぎ・・・
  • WindowManagerェ・・・
  • パッケージ更新頻度・・・
  • うっかりカーネルアップデートすると対処大変

# 浪漫だけではダメですね。現実も見ます・・・

というわけなので、現在はこんな感じでDashboard表示端末になっています

DSC_0831.JPG

今回では、ご自宅で運用できるDashboardの作り方をご紹介します

# Dashboard自体は、一昔前にkibanaで〜とかで流行ったかもしれないですが笑

材料


こんなところです。

取り回し上問題にはなりませんが、7インチディスプレイの欠点は、下記かなと思います。

  • フレームの精度がイマイチ
    • 微妙にフレームサイズ、厚みがありそうでないことも
    • シールでフレームを積層するけど、シールの粘着力が弱すぎる・・・
  • 脚が異常に固い
    • 取り外し可能そうと思いきや、精度が悪くてめちゃくちゃ固いです
      • 無茶してはずそうとして、微妙に折れそうになりました・・・
    • 取り付けも大変
  • Raspberry pi本体のGPIOからも給電できるが、給電するとキーボードが動かない
    • 個体差なのかな?と思いつつちゃんと測定してません笑
    • 恐らく、モニターへの給電でいっぱいいっぱいでキーボードへの給電が出来なくなるったからだろうと推測

ぐらいでしょうか。
使用感は特に問題なく、至って普通のタッチスクリーンです

Dashbordとして欲しいもの


こんなところがあれば、常用のDashboardとしては十分でしょう

  • 時計
    • 時間が表示してあると嬉しいですよね
    • Time is money.
  • 路線情報
    • 通勤に使うものの情報が出てないと困りますよね
    • 遅延連絡とか必要ですし笑
  • トレンド情報
    • 今、このときに流行っているものがあれば会話の引き出しになる(かも・・・)
    • パッとそのときどきのトレンドがあるといいでしょう

これがお仕事とかになると、サーバのメトリクス各種施策のKPI表示とかになります
が、個人であればこれぐらいで十分でしょう

Dashbordを作る


さて、物理的には、Dashboard環境を用意することができました。
ではここからソフトウェア的に準備をしていきたいと思います。

今回は、Smashingというgemを作ってDashboardを作りたいと思います。

因みにこのgemですが、元々はShopifyが出しているdashingというgemの後継のものです。
Sinatraベースのf/wでTVとかでデカイモニターとかに最適化できるようになっているようです。
(TVでは映しませんが笑)

小並感な感想

  • 言語がRuby
    • 遊びでやるにはちょうどいい
  • 独自widgetが作れて、公開可能
    • 無ければ、使いませんよね・・・
    • widgetの生成もDSLでできる
    • 基本的なサンプルwidgetもデフォルトで用意されている
  • 公開されたwidgetの追加が容易
    • こちらに一覧があります
    • 著名な外部サービス連携のものは大体揃っている印象
  • Sinatraベース
    • デフォルトではないものの認証系もその気になればさくっと実装できる
    • Dashboardの並べ替えもdrag/dropで容易
    • web serverがthinかーというモニョところはある
  • wikiが豊富
    • READMEにちょこっと書いてあるレベルではなく、きちんと実装方法まで書かれている
    • トラブルシューティングも容易
    • 起動スクリプトも用意されている
    • tipsも存在している
  • 開発は活発か・・・
    • 程よくメンテはされているみたい
    • issue&PRもそれなりにある形
    • このご時世にcoffeeかーというモニョるものは一定ある

プロジェクトの作成


ここまではREADME通り

$ gem install smashing --no-ri --no-rdoc
$ smashing new dashboard
$ cd dashboard
$ bundle install --path=vendor/bundle
$ smashing start

http://localhost:3030にアクセスすると下記のような画面になります

image.png

# 実際には画面が動いているので、それなりにオシャンティー(なように見える・・・)

ディレクトリ構造


利用可能なwidget一覧

ここの内容をdashboardメイン画面に追加していく形

widgets/
├── clock
│   ├── clock.coffee
│   ├── clock.html
│   └── clock.scss
├── comments
│   ├── comments.coffee
│   ├── comments.html
│   └── comments.scss
├── graph
│   ├── graph.coffee
│   ├── graph.html
│   └── graph.scss
├── iframe
│   ├── iframe.coffee
│   ├── iframe.html
│   └── iframe.scss
├── image
│   ├── image.coffee
│   ├── image.html
│   └── image.scss
├── list
│   ├── list.coffee
│   ├── list.html
│   └── list.scss
├── meter
│   ├── meter.coffee
│   ├── meter.html
│   └── meter.scss
├── number
│   ├── number.coffee
│   ├── number.html
│   └── number.scss
└── text
    ├── text.coffee
    ├── text.html
    └── text.scss

Rubyコード

定期実行したい処理とかはここに書く形

jobs/
├── buzzwords.rb
├── convergence.rb
├── sample.rb
└── twitter.rb

Dashboardメイン画面

dashboards/
├── layout.erb
├── sample.erb
└── sampletv.erb

自前でDashboardを作ってみる


大枠の動かした方と編集ファイルのディレクトリが理解できたので、独自widgetを追加してみます

路線情報取得

まずは、jobファイルを作成します

$smashing generate job lines
       exist  jobs
      create  jobs/lines.rb
  • 路線情報の取得は、Yahoo運行情報から取得します
    • コードが雑なのは(ry
  • 2時間に一度更新するようにします
    • SCHEDULER.everyの引数に指定しているものです
    • wheneverのcron設定と書き方は似ています
require 'mechanize'

SCHEDULER.every '120m', :first_in => 0 do |job|
  agent = Mechanize.new
  page = agent.get("https://transit.yahoo.co.jp/traininfo/area/4/")
  items = []

  jy_status = page.search("#mdAreaMajorLine div:nth-child(4) table tr:nth-child(2) td:nth-child(2)").text
  jy_detail = page.search("#mdAreaMajorLine div:nth-child(4) table tr:nth-child(2) td:nth-child(3)").text
  items << { name: "山手線", status: jy_status, detail: jy_detail }

  send_event('lines', { items: items }) unless items.empty?
end

路線情報表示widget

まずは、路線情報表示用のwidgetを作成します

$smashing generate widget lines
       exist  widgets
      create  widgets/lines/lines.coffee
      create  widgets/lines/lines.html
      create  widgets/lines/lines.scss

表示用のwidgetを編集

<div class="header">
  <h1 class="header__title">路線情報</h1>
</div>

<li class="content-area">
  <div class="content-area__container" data-foreach-item="items">
    <div class="content-area__container__information">
      <span class="content-area__container__information--name" data-bind="item.name">山手線</span>
      <span class="content-area__container__information--status" data-bind="item.status">平常運転</span>
      <span class="content-area__container__information--detail" data-bind="item.detail">事故・遅延情報はありません</span>
    </div>
  </div>
</li>

装飾のSass

  • 表示用のアイコンは素材サイトから借りてきました
  • 記述量や設定する内容も小さいので、シングルクラスでサクッと
    • 雑すぎてモヒカンな人には殴られるかも笑
.widget-lines {
    background-color: #008fde;

    .header {
        display: flex;
    }
    .header__title {
        color: rgba(255, 255, 255, 0.7);
        margin-bottom: 0px;
        background: url('http://icooon-mono.com/i/icon_11947/icon_119470_256.png') no-repeat;
        background-size: 45px 100%;
        padding-left: 45px;
        margin: 0 auto;
    }
    .content-area__container {
        width: 90%;
    }
    .content-area__container__information {
        display: grid;
        margin: 5%;
    }
   .content-area__container__information--name {
       font-weight: bold;
       font-size: 24px;
       margin-bottom: 10%;
   }
   .content-area__container__information--status {
       font-weight: bold;
       font-size: 18px;
    }
   .content-area__container__information--detail {
       font-size: 12px;
       margin-bottom: 10%;
   }
}

最後にレイアウトファイル

作成したwidgetを表示できるようにします

  • dashboard/sample.erb を編集します
  • widgetを追加します
    • jQuery gridsterの設定
      • data-row
      • data-col
      • data-sizex
      • data-sizey
    • widgetの設定
      • data-id: jobファイルで設定したsend_eventの第一引数を設定
      • data-view: 表示するwidgetを設定
<% content_for :title do %>My super sweet dashboard<% end %>
<div class="gridster">
  <ul>
    <li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
      <div data-id="lines" data-view="Lines"></div>
    </li>
  </ul>
</div>

Dashboardの起動

面倒なので、Herokuで動かします
* 個人だとsystemd-nspawnで動いてるコンテナで動かしてるので、Herokuは使ってませんが・・・
* 半分くらいsystemd-nspawnを動かすネタとして作ってた部分も否めない><

Procfileを適当に作成

起動コマンドをそのまま書く形でOK

dashboard: bundle exec smashing start

Heroku上で動かす

普通にHerokuのアプリを作って、pushするぐらいですね

$ heroku create
$ git push heroku master
$ heroku open

ということで、Dashboardの完成形

こんな感じになって、お手軽かつ良い感じに以下の情報を取得することができましたね

  • 時間
  • 路線状況
  • 流行りの情報
    • 忘れないうちにこの記事を書いていた、12/4はM-1グランプリでとろサーモンさんが優勝されたようです
    • おめでとうございますm(_ _)m

image.png

冒頭の画像にもあるように実際にはタッチスクリーンの画面サイズが小さいのでうまく収まっていないです。
ここはSassを調整すれば改善可能でしょう。
運用上、気になってくるようだったら、調整していこうかなと思います

応用すれば、結構個人用途で色々できそうですw

  • 天気予報表示したり
  • 株価とか仮想通貨の推移とかグラフ表示したり
  • デジタルフォトフレームとか作れたり
  • GithubのPRをリスト表示したり

半年ほど運用していますが、満足感はあるんですが・・・
もうちょっと表示する情報は多くしてもいいかなと思ってます

ソースコードはこちらに置いておきます