Metabase+NatureRemoで部屋環境を可視化する【プロト実装編】
前回,Go言語とRaspberryPiの環境構築の話を書きました.
shikky-lab.hatenablog.com
実はこれが今回の話に繋がるのですが,Go言語+ラズパイで部屋環境(温度,湿度ほか)の可視化にチャレンジしています.
とはいえポイントはそちらではなく,今回タイトルに挙げたMetabaseと,温湿度計を一応内部に備えているNatureRemoになります.
まだまだ未完成なのですが,ひとまずプロト実装が動いたので,その内容について書いていきたいと思います.
システム構成
初めにシステム構成載せときます.
1. Metabase
Metabaseはオープンソースのデータ可視化ツールです.データだけ食わせれば,それを使ってグラフ等をカスタマイズして表示することができます.Excelのグラフ機能のようなものですね.
こういった可視化ツールは実は世の中に沢山あって,
- Grafana : Grafana: The open observability platform | Grafana Labs
- Kibana : Kibanaについて | Elastic
あたりが有名みたいです.
他にもいろいろあるようですが,
OSSのデータ可視化ツール「Metabase」が超使いやすい - Qiita
様のエントリなどを見るとMetabaseが簡単かつ良さげだなと思い,こちらを使うことにしました.
なおMetabaseの魅力はそちらで詳細に紹介されているので,今回は割愛します.
さておき,次に考えるのはMetabaseが使用するデータを格納するためのデータベースとなります.
2. MySQL(MariaDB)
正直DBは何でもよかったので,一番一般的なヤツを採用しました.
ちなみにRaspbian(というかdebian系のLinux)ではMySQLではなく,それをフォークしたMariaDBというものを採用しているらしいです.
MariaDB - Wikipedia
なのでaptでインストールするときもmariadbを指定しましょう.
3. 常駐スクリプト
これも定期的に値をとってきてDBに書き込むだけなので,なんでもOKでした.なので今回はGo言語を使ってみることにしたというわけですね.
NatureRemoへのアクセスは,要はREST-APIを叩くだけとなります.アクセスのためには事前に生成したトークンを読み込ませる必要があるのですが,手順は以下のエントリを参考にさせて頂きました.
Nature Remoの公式APIの使い方 - Qiita
以下,軽くコードを解説していきます.コード全体はコチラ.
GitHub - shikky-lab/omni_dashboard at 34aa6b039699ec081e98dc2381c842382e3b23ff
Nature Remoへのアクセス
取得部分のコードはこんな感じ
token:="XXX" client := http.Client{} url := "https://api.nature.global/1/devices" req, err := http.NewRequest("GET", url, nil) req.Header.Add("accept", "application/json") req.Header.Add("Authorization", "Bearer "+string(token)) resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() //ここで受け取ったrespのbodyにnatureRemoから取得した値がJsonとして格納されている. //そのjsonに合わせたtypeを事前に定義しておくと,以下のように格納できる. byteArray, _ := ioutil.ReadAll(resp.Body) var devices []remoDevice if err := json.Unmarshal(byteArray, &devices); err != nil { panic(err) }
↑で使っているremoDeviceなる構造体は↓のような感じです.Remoが返してくるjsonに合わせて定義してあります.
type illuminanceValue struct { Val float32 `json:"val"` CreatedAt time.Time `json:"created_at"` } type humidityValue struct { Val float32 `json:"val"` CreatedAt time.Time `json:"created_at"` } type movedValue struct { Val float32 `json:"val"` CreatedAt time.Time `json:"created_at"` } type temperatureValue struct { Val float32 `json:"val"` CreatedAt time.Time `json:"created_at"` } type events struct { Hu humidityValue `json:"hu"` Il illuminanceValue `json:"il"` Mo movedValue `json:"mo"` Te temperatureValue `json:"te"` } type remoDevice struct { Name string `json:"name"` ID string `json:"id"` CratedAt time.Time `json:"crated_at"` MacAddress string `json:"mac_address"` SerialNumber string `json:"serial_number"` FirmwareVersion string `json:"firmware_version"` TemperatureOffset int `json:"temperature_offset"` HumidityOffset int `json:"humidity_offset"` Users []user `json:"users"` NewestEvents events `json:"newest_events"` }
こうしておくと自動的に構造体のフィールドとして値が格納されるので,非常に使いやすくなります.
DBへの書き込み
プログラム上でDBを扱う場合,SQL文を直接叩いても良いのですが,いずれ面倒になりそうなのでORMapperを導入します.
Go言語におけるORMapperとしては,GORMというものが良く使われているようです.
GORMガイド | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
これも先ほどのRESTの時と同様に,DBのスキーマに合わせた構造体を定義しておくと,構造体を経由してDB書き込みなどができるようになります.
つまりこんな感じで構造体を定義しておくと,
type humidity struct { ID int `gorm:"cloumn:id"` //タグつけるとcloumn名と紐づけ.なけらばField名が使われる. Value float32 Time time.Time }
こんな感じで書き込みできます.(テーブルは事前に用意されている前提)
humidityOrm := humidity{} humidityOrm.Value = devices[0].NewestEvents.Hu.Val//deviceはさっきのRESTのスニペットで取得したやつ humidityOrm.Time = devices[0].NewestEvents.Hu.CreatedAt //dbinfoは後述 CONNECT := dbinfo.user + ":" + dbinfos.Pass + "@" + dbinfos.Protocol + "/" + dbinfos.Dbname + "?" + dbinfos.Param db, err := gorm.Open(dbinfos.Dbms, CONNECT) db := gormConnect() defer db.Close() db.Save(&humidityOrm)
なおスクリプト内に出てきたdbinfoは要はdbへの接続情報ですが,私は以下のようにyamlファイルとして書き出していたやつを読み込ませてます.
(パスワードとかをコードに入れるとGitHubにpushできないので)
# dbinfo.yml dbms : mysql user : root pass : [パスワード] protocol : tcp(localhost:3306) dbname : omni_dash_dev param : charset=utf8mb4&parseTime=True&loc=Asia%2FTokyo
あとはこれを5分に一回くらいの頻度で定期的に叩くようにすれば,DBにデータを蓄積していけます.
ちなみにNatureRemoはセンサの値に変化があるたびに,その値をタイムスタンプとともに内部に保持しています.
そしてRESTで叩いた時に得られる情報はその最新の値になります.
つまり,センサの値に変化がなければ同じデータが返ってきます.
特に温度計のデータは分解能が0.6度なので,数時間値が変わらないこともザラです.
ですのでNatureRemoに頻繁にアクセスしたとしても,常に新しいデータが返ってくるわけではないので,DBのデータがあふれる心配はあまりしなくて大丈夫です.
これからやること
さしあたりここまでで温度と湿度の可視化はできました.これからの展望としては,下記を考えています.
- 温湿度の精度向上
- NatureRemoの温度計の分解能は0.6度と大き目 &温湿度計の精度が提示されていない
- ⇒精度を謳っているSwitchBotの温湿度計を買ってみました.現在実装中.
- www.switchbot.jp
- CO2濃度の可視化
- AliExpressで買ったCO2センサが届いたので,こちらも搭載予定
- インターネット上からアクセス可能にする
- ngrokなるサービスを使えば実現できそう
- 参考: ngrokが便利すぎる - Qiita
- Andoroidのウィジェット対応
- スマートウォッチなどの情報を可視化する
- ゆくゆくは取得しているデータすべてをグラフ化したい
ざっと挙げただけでも山盛りですね(笑).
なかなか長い闘いになりそうですが,気長に進めていこうかなと思います.
ちなみにプロジェクト名は"Omni Dashboard"と名付けました.
どうでもいいですが,プロジェクト名つけるとモチベーション上がりません?私だけ?
プロジェクトが頓挫しないよう,粛々と頑張っていきたいと思います.
それでは.