この記事は、Noodl Advent Calendar 2019 12日目の記事です。
@kn1chtと申します。もともとやりたかったネタが頓挫したため、その過程でできたものを記事化することにします。
昨日11日は@kisaichi07さんの「NoodlでUIデザインをしよう!インフォグラフィック編」でした。この日は別の勉強会にいて動画全体を拝見してはいませんが、HTML Contentsに{{ }}
でデータを渡せるのは知らなかったので参考になりました。
明日の記事は@kmaepuさんの「ラズパイとNoodlでデジタルサイネージを作った話」です。
TL;DR
-
Noodlで
obniz.js
を読み込むことで、obnizに直接アクセスすることに成功しました - ただし、Noodl内のプレビューでは動作しません
- 現在のNoodl 1.3.1ではElectronのバージョンが古く、
async
が使えないためです - より新しいNoodlを使うか、ブラウザでプレビューを開くことで対処できます
- 現在のNoodl 1.3.1ではElectronのバージョンが古く、
作ったプロジェクトは以下のGistに置いてあるので、obnizをお持ちの方はお試しください(obniz idの部分は空欄にしてあるので、お手元のobnizのidを入力してください)。
はじめに:Noodlとobniz
Noodlとは
Noodlは、ノードを繋いで簡単にUIのプロトタイピングができるスウェーデン発のツールです。プロトタイプといっても実際にデータをやり取りでき、MQTTなどで外部と通信も可能なので、趣味のIoTプロジェクトにぴったりのツールです。
使い方や雰囲気はNoodl Advent Calendar 2019の各記事を見ていくとなんとなく分かることでしょう(丸投げ)。
obnizとは
Webから操作できるIoTボードです。これまでのマイコンボードはパソコンと繋いで、プログラムを書き込んで……というのが普通でしたが、obnizでは全てがWebで完結します。
クラウド経由でAPIを叩くかのようにハードウェアを操作できるので、ハードウェアの面倒な部分と格闘せずにシュッとIoTシステムを作れます。
Noodlとobnizの連携方法
Noodlとobnizという先進的なツールを見れば、組み合わせて色々やりたくなるのは当然です。
このカレンダーでも、 @tseigo さんがゆるメカトロ車をNoodl製のUIで操作する記事を公開しておられます。
やり方は様々ですが、Noodl側とobniz Cloud側をMQTTやREST APIの通信でつなぎ、必要に応じてenebularなどを間に入れる方法がよく使われています。
いわゆる**IoTフルスタック構成**に近い感じですね。
これはこれで汎用性があって使いやすいのですが、全くの初心者が試すとなると、多数の知らないツールやサービスをいきなり駆使しなければなりません。
そこで、Noodlから直接obnizを動作させられないか試してみました。
環境
-
Noodl 1.3.1
- Noodlの最新の安定版です
- 1.4や2.0などより新しいバージョンも存在しますが、beta版で細かい挙動が異なるようです
- 本記事の発展バージョンのNoodlとobnizでぐりぐりしてみるでは、Noodl 1.4.0で動作しています
アプローチ
obnizの仕組みを読むと分かる通り、obnizはobniz Cloudが提供するAPIに各種言語のSDKからアクセスすることで動きます。
obniz開発者コンソールでコードを書いて動かすのが最も手軽ですが、実際には**obniz.js
さえ使えればどこでJavaScriptを実行しても動きます**(例えばローカルのエディタでHTMLを書いてブラウザで開いてもOKです)。
NoodlはScript Downloaderというノードで外部のJSを取得できるので、obniz.js
を使うこともできそうです。
上の記事にある通り、Script Downloader + Javascript + HTML Contentの3連コンボが基本形です。
obnizクイックスタートにあるHTMLのサンプルコードを基に実装することとします。
ノードの準備
Script Downloader
obnizのサンプルで読み込まれているのはjquery-3.2.1.min.js
とobniz.js
の2つです。
URLをExternal scriptsにコピペでOKです。
HTML Content
サンプルコードの<html></html>
の中身を全てContent > HTMLにコピペします。
ただし、JSは他のノードで動かすので<script>
タグのみ消去しておきます(本当はJavaScriptも全部HTML Contentの中で動くのかもしれませんが、それだとNoodlを使う意味がなさすぎるのでやりません)。
また、starter-sample.css
というスタイルシートが相対パス指定になっているので、URLに書き換えます。
- <link rel="stylesheet" href="/css/starter-sample.css">
+ <link rel="stylesheet" href="https://obniz.io/css/starter-sample.css">
Javascript
ここは少し工夫が必要です。サンプルコードの<script></script>
で囲まれた部分をrun
にコピペするだけでは動きません。
obniz.onconnect = async function() {
の行にエラーが出ています。これはasync
の指定を取り除けば消えます(理由は後述します)。
他2つのノードと連携するために、inputs
をこのように定義します(この辺りはNoodlで外部JSライブラリ読み込み(グラフ表示)と同様です)。
inputs: {
isAddedToDOM : "boolean",
domElement : "domelement",
scriptsLoaded: "boolean"
},
ノード同士を繋ぎます。特に自分でコードを書かなくても、この通りに設定すれば外部スクリプトの読み込み完了を待ってくれたり、自分で書いたJSからdocument
が利用可能になったりするようです。
プレビューが動作しない問題の調査
これで動くはずですが、Javascriptノードの周りに赤い点線が出ていますね。Noodlエディタの右上に警告マークが出ているので見てみましょう。
Obniz is not defined
だそうです。obniz.js
は読み込んでいるので定義されていないはずはないのですが……。
Noodlでは、デバッグボタン(右上に並んでいる虫のアイコン)から"OPEN WEB DEBUGGER"ボタンを押すことで皆さんおなじみのChrome開発者ツールを開くことができます。原因のよくわからないエラーが出ていたらまずここで確認すると早いと思います。
obniz.js
の途中でエラーが出て止まっていました。この部分を見てみると、次のようになっています。
async loop() {
if (typeof this.looper === 'function' && this.onConnectCalled) {
let prom = this.looper();
...
async loop() {
の行がシンタックスエラーを起こしたようです。Javascriptノードでも、async
を消したらエラーが消えました。もしやNoodl自体がasync/awaitに対応してないのでは? と思ったので調べてみました。
※async/await (Async Functions)が何かは本筋に関係ないので説明しません。知らない方も、最近のJavascriptに増えた新機能ということだけ押さえていただければ大丈夫です。
Noodlではasync/awaitが使用できない
Noodlのメニューからバージョン情報を見ることができます。
- Noodl 1.3.1
- electron : 1.4.13
- chrome : 53.0.2785.143
- node : 6.5.0
- v8 : 5.3.332.47
Electron 1.4.13は2016年12月に出たバージョンで、現行に比べるとかなり古いものです。Chromeがasync/awaitに対応したのはバージョン55以降なので、Noodl 1.3.1に内蔵されているElectronはasync/awaitを使えないものだと分かります。こればかりはNoodl側が新しいバージョンに対応しない限りどうすることもできません。
※Noodl 1.4や、このほど発表されたNoodl 2.0では対応しているようです。これらをお使いの方には以下の回避策は不要です。
回避策:ブラウザでプレビューを開く
文法レベルで非対応なら仕方ないか……と諦める所でしたが、Noodlのプレビューはブラウザでも開けるのを思い出しました。PCやスマホに入っている最新のブラウザならasync/awaitを使ったobniz.js
も読み込めるはずです。
ブラウザで開くのは簡単で、エディタ右上のスマホアイコンを押して出てくるURLを開くだけです。
あっさり動きました。obnizのIDをぼかしていますが、上に緑色で"online: {obniz id} via internet"と出ているので無事繋がっているのが分かります。
もちろんサンプル部分も問題なく動いてます。
(Advent Calendar記事用動画)
— kn1cht (@kn1cht) December 11, 2019
obnizクイックスタート(https://t.co/rif0SjaPsb)にあるサンプルコードをNoodlに移植して動かしている様子です#Noodl #obniz pic.twitter.com/YkAp9rgDOr
まとめ
Noodlから直接obnizを動かすことができました。本記事ではUI部分をobnizのサンプルHTMLコードからそのまま流用しましたが、Noodlの強みであるUIとobniz.js
を組み合わせることももちろん可能です。
この方法の使い道は何でしょうか? 初心者が試す時云々と述べて始めたものの、ブラウザで別に開かないと動かないのは初心者の混乱を招きそうです。また、JavascriptやHTMLのコードをそのまま扱うので、ノンコーディングというNoodlのメリットがあまり活かせていません。
やはりobnizのコードはobnizの開発者コンソールに置いておき、Noodl側ではUIの処理だけに集中した方が見通しが良さそうです。
とはいえ、思いついた実装を短時間で試してみたいような場合には、とりあえずNoodlから直でobnizを動かすというのも手軽でいいと思います。今回作ったobniz.js
関連のノードをコンポーネントにまとめておき、ライブラリとして呼べるようにしておくと使いやすいかもしれませんね!
蛇足(もともとやりたかったこと)
obnizは128x64のディスプレイを持っており、文字や図形を表示できます。
obnizのAPIで文字などを出すこともできますが、JS側でcanvasに描画しておいてコンテキストを渡せば画面に反映されます。
Noodlの画面もcanvasでレンダリングされるようなので、Noodlで構築した画面をそのままobnizに表示することを目論んでいました。ただ、Noodl内部でNoodlの画面をcanvasとして取得する方法が見つからず断念しました。