LoginSignup
4
1

More than 3 years have passed since last update.

enebular-agentで表示端末を作る

Last updated at Posted at 2020-12-05

image.png

enebular-agentを使って情報を表示するための端末を作ってみたいと思って、ちょっと試行錯誤しながら作ってみました。
enebular-agentはRaspberry Piに対応しているので、Raspberry PiとRaspberry Piの上に搭載できるHDMI入力の液晶モジュールを使って、表示端末を作ってみたいと思います。
今回、表示する内容は現在の天気としました。

準備するもの

表示端末としての設定

enebular-agentは、バックグランドとして動作するアプリケーションのため、ウィンドウを持ちません。そのため、情報を表示するためにdashboardノードを使用します。
dashboardノードの出力はブラウザで表示できるので、フローの起動時にブラウザをフルスクリーン表示するようにすればディスプレイでフローで作った情報を確認できます。
また、Raspberry Piの初期設定状態だとしばらくすると画面がスリープしてしまうので、スリープしないようにする設定もフローから行います。

dashboardノード

dashboardノードはフローに配置するとブラウザ上にUIを作れるノードです。例えば以下のようになります。

  • フロー
    image.png

  • ブラウザ上の表示
    image.png

enebularではdashboardノードが標準ノードとして組み込まれているのでノードを追加する必要はありません。

ブラウザをフルスクリーンで起動

ブラウザはRaspberry Pi標準のChromiumをコマンドで起動します。コマンドの実行にはexecノードを使用します。
フロー上では、ブラウザを表示するディスプレイを指定する必要があるので、その指定とフルスクリーン表示するためのオプション、URL(dashboardノード出力先のURL)を引数とし、以下のコマンドになります。

DISPLAY=:0 chromium-browser --noerrdialogs --kiosk --incognito http://localhost:1880/ui

これをexecノードのコマンド欄に設定します。

スリープしないようにする

ディスプレイをスリープしないようにするには以下のコマンドを実行します。

xset -dpms
xset s off
xset s noblank

これもexecノードのコマンド欄にディスプレイを指定して、連続で実行されるように設定します。

DISPLAY=:0 xset -dpms;DISPLAY=:0 xset s off;DISPLAY=:0 xset s noblank

天気予報取得

表示する天気予報はOpenWeatherMapというおそらく一番有名な天気情報を取得するAPIを使って取得します。
アカウント登録(無料)を行ってAPIキーを取得すれば、指定した緯度経度の天気情報が取得できます。

東京の天気情報を取得するクエリの例です。

https://api.openweathermap.org/data/2.5/onecall?lat=35.681236&lon=139.767125&units=metric&lang=ja&appid={APIキー}

以下の様にJSON型でレスポンスが返ってきます。

{
    "lat": 35.68,
    "lon": 139.77,
    "timezone": "Asia/Tokyo",
    "timezone_offset": 32400,
    "current": {
        "dt": 1607188618,
        "sunrise": 1607204202,
        "sunset": 1607239652,
        "temp": 8.56,
        "feels_like": 4.13,
        "pressure": 1024,
        "humidity": 76,
        "dew_point": 4.58,
        "uvi": 0,
        "clouds": 75,
        "visibility": 10000,
        "wind_speed": 4.6,
        "wind_deg": 360,
        "weather": [
            {
                "id": 803,
                "main": "Clouds",
                "description": "曇りがち",
                "icon": "04n"
            }
        ]
    },
    "minutely": [
      ・・・省略・・・
    ],
    "hourly": [
      ・・・省略・・・
    ],
    "daily": [
      ・・・省略・・・
    ]
}

フロー

これまでの内容を組み合わせたフローが以下となります。

image.png

[{"id":"e98aabc1.0347c8","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"85407b90.7d4138","type":"inject","z":"e98aabc1.0347c8","name":"フロー起動時に1回のみ","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"2","x":190,"y":200,"wires":[["53632fbe.f963a","cc26bd5c.b8bca","f52f3df2.aee3a"]]},{"id":"53632fbe.f963a","type":"exec","z":"e98aabc1.0347c8","command":"DISPLAY=:0 chromium-browser ","addpay":false,"append":"--noerrdialogs --kiosk --incognito http://localhost:1880/ui","useSpawn":"false","timer":"","oldrc":false,"name":"","x":490,"y":220,"wires":[[],[],[]]},{"id":"b3703400.f25008","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":2,"width":0,"height":0,"name":"","label":"時刻","format":"{{msg.payload.time}}","layout":"row-left","x":830,"y":340,"wires":[]},{"id":"f52f3df2.aee3a","type":"http request","z":"e98aabc1.0347c8","name":"","method":"GET","ret":"obj","paytoqs":false,"url":"https://api.openweathermap.org/data/2.5/onecall?lat=35.681236&lon=139.767125&units=metric&lang=ja&appid={API Key}","tls":"","persist":false,"proxy":"","authType":"","x":350,"y":420,"wires":[["6753aba1.420674","e1ab93f4.ba407","3d3e17fe.542668"]]},{"id":"d12b5235.ecffb","type":"inject","z":"e98aabc1.0347c8","name":"5分周期","topic":"","payload":"","payloadType":"date","repeat":"300","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":420,"wires":[["f52f3df2.aee3a"]]},{"id":"6753aba1.420674","type":"function","z":"e98aabc1.0347c8","name":"現在の天気情報を分解","func":"var json = msg.payload;\nconst dt = new Date(json.current.dt * 1000 + ((new Date().getTimezoneOffset() + (9 * 60)) * 60 * 1000));\nvar text;\n\nmsg.payload.date = dt.getFullYear() + '年'\n        + (dt.getMonth() + 1) + '月'\n        + dt.getDate() + '日 ';\n\nmsg.payload.time = dt.getHours() + '時'\n        + dt.getMinutes() + '分'\n        + dt.getSeconds() + '秒\\n';\n\n\nmsg.payload.temp = json.current.temp + '℃';\nmsg.payload.humidity = json.current.humidity + '%';\nmsg.payload.pressure = json.current.pressure + 'hPa';\nmsg.payload.weather = json.current.weather[0].description;\nmsg.payload.rain = 0;\nif('rain' in json.current) {\n    if('1h' in json.current.rain){\n        msg.payload.rain = json.current.rain[\"1h\"];\n    }\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"x":580,"y":420,"wires":[["b3703400.f25008","a843f73a.c73d88","79b30ea7.fdb4","e0459366.3c27f","8ba22476.d72fc8","5458a957.1e2b08","ae888926.2b90e8"]]},{"id":"a843f73a.c73d88","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":3,"width":0,"height":0,"name":"","label":"気温","format":"{{msg.payload.temp}}","layout":"row-left","x":830,"y":380,"wires":[]},{"id":"79b30ea7.fdb4","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":4,"width":0,"height":0,"name":"","label":"湿度","format":"{{msg.payload.humidity}}","layout":"row-left","x":830,"y":420,"wires":[]},{"id":"e0459366.3c27f","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":5,"width":0,"height":0,"name":"","label":"気圧","format":"{{msg.payload.pressure}}","layout":"row-left","x":830,"y":460,"wires":[]},{"id":"8ba22476.d72fc8","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":6,"width":0,"height":0,"name":"","label":"天気","format":"{{msg.payload.weather}}","layout":"row-left","x":830,"y":500,"wires":[]},{"id":"5458a957.1e2b08","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":7,"width":0,"height":0,"name":"","label":"降水量(1時間当たり)","format":"{{msg.payload.rain}}","layout":"row-left","x":880,"y":540,"wires":[]},{"id":"8923cbfd.6484a8","type":"ui_chart","z":"e98aabc1.0347c8","name":"","group":"95aa5e6a.2039a","order":6,"width":"5","height":"5","label":"気温","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":830,"y":580,"wires":[[]]},{"id":"e1ab93f4.ba407","type":"function","z":"e98aabc1.0347c8","name":"現在気温を抽出","func":"var json = msg.payload;\nconst dt = new Date(json.current.dt * 1000 + ((new Date().getTimezoneOffset() + (9 * 60)) * 60 * 1000));\n\nmsg.payload = json.current.temp;\n\nreturn msg;\n","outputs":1,"noerr":0,"x":580,"y":580,"wires":[["8923cbfd.6484a8"]]},{"id":"3d3e17fe.542668","type":"function","z":"e98aabc1.0347c8","name":"現在気圧を抽出","func":"var json = msg.payload;\nconst dt = new Date(json.current.dt * 1000 + ((new Date().getTimezoneOffset() + (9 * 60)) * 60 * 1000));\n\nmsg.payload = json.current.pressure;\n\nreturn msg;\n","outputs":1,"noerr":0,"x":580,"y":640,"wires":[["c1abef76.8fe13"]]},{"id":"c1abef76.8fe13","type":"ui_chart","z":"e98aabc1.0347c8","name":"","group":"95aa5e6a.2039a","order":6,"width":"5","height":"5","label":"気圧","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":830,"y":640,"wires":[[]]},{"id":"ae888926.2b90e8","type":"ui_text","z":"e98aabc1.0347c8","group":"65b0e5ae.ce33dc","order":1,"width":0,"height":0,"name":"","label":"日付","format":"{{msg.payload.date}}","layout":"row-left","x":830,"y":300,"wires":[]},{"id":"cc26bd5c.b8bca","type":"exec","z":"e98aabc1.0347c8","command":"DISPLAY=:0 xset -dpms;DISPLAY=:0 xset s off;DISPLAY=:0 xset s noblank","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":630,"y":160,"wires":[[],[],[]]},{"id":"65b0e5ae.ce33dc","type":"ui_group","z":"","name":"現在の天気予報","tab":"d6259073.9e544","order":1,"disp":true,"width":"5","collapse":false},{"id":"95aa5e6a.2039a","type":"ui_group","z":"","name":"グラフ","tab":"d6259073.9e544","order":2,"disp":false,"width":"5","collapse":false},{"id":"d6259073.9e544","type":"ui_tab","z":"","name":"ホーム","icon":"dashboard","disabled":false,"hidden":false}]

※使用する場合はhttp requestノードのURLで{API key}の部分を書き換えてください。

このフローをenebular-agentにデプロイすれば現在の天気情報+気温と気圧の変化グラフを表示するための端末ができあがります。

さらに

enebular-agentは普通にインストールするとRaspberry Piが起動するだけで、裏で起動し、フローでブラウザが起動するので、電源を入れるだけで表示端末として機能するのですが、表示端末として使用する場合はマウスカーソルが邪魔になります。
マウスカーソルを非表示にするためには以下のコマンドでunclutterをインストールし、再起動すれば非表示になります。

> sudo apt-get install unclutter

ただ、今回はこのインストールをenebularのファイルデプロイ機能を使ってやってみました。

ファイルデプロイ機能はファイルをenebular-agentにデプロイできる機能です。デプロイする際にファイルを実行できるので、シェルスクリプトのファイルを用意して、インストールするコマンドを実行するようにします。シェルスクリプトのファイルの内容を以下のようにしました。

mouseCursorDisable.sh
#!/bin/bash

sudo apt-get install unclutter
sudo reboot

このファイルをファイルアセットとしてenebularに登録します。(Excute On DeployをONするとデプロイ時に実行されます。)
image.png

登録が完了したらenebular-agentにデプロイするとインストール後、自動的に再起動してマウスカーソルが表示となりました。

端末を複数用意する場合など、1台1台インストールするのが面倒な場合はスクリプトを作って、enebularからファイルデプロイすると楽です。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1