Edited at
IBM CloudDay 23

Node-REDでJavaが使えるJava functionノードで遊んでみる

More than 1 year has passed since last update.

今回は、Node-RED上でJavaのコードを実行できるJava functionノードを使ってみます。開発者が便利に使えそうなフローの例も紹介します。

Java functionノード(node-red-contrib-java-function)

https://flows.nodered.org/node/node-red-contrib-java-function


Java functionノードとは

 Node-REDで標準で用意されているfunctionノードはJavaScriptでコードを書く必要があるため、JavaScriptに慣れていない開発者は苦戦することがあります。この問題を解決するために、Node-REDのライブラリには、pythonなどの他言語で記述できるfunctionノードが公開されています。今回紹介するJava functionノードは、その中でもJavaのコードを実行できるfunctionノードです。本ノードを用いることでJavaが持つ豊富な標準ライブラリをNodde-REDから呼び出すことができます。


Java functionノードの開発例

 さっそくJava functionノードを使った例を6つ紹介します。Java functionノードを用いることで、これまでのNode-REDでは難しかった機能を手軽に実現できます。


(1) スピーカから音を出す

 Windows 10の場合は「ポロロン」、macなら「ツン」というOSのシステム音を鳴らせてみます。Java functionノードにToolkitクラスのbeep()メソッドを記載するのみで実装できます。

beep.png

 このフローではinjectノードのボタンをクリックすると、システム音が鳴ります。JavaFxを用いるとmp3ファイルの再生もできそうですね。


スピーカから音を出すフロー

[{"id":"7668777e.580ae8","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":"","x":160,"y":260,"wires":[["f5974570.d119d8"]]},{"id":"f5974570.d119d8","type":"javafunction","z":"3cd542b9.3985de","name":"beep sound","func":"Toolkit.getDefaultToolkit().beep();\nreturn msg;","outputs":1,"x":310,"y":260,"wires":[["279508d1.f18468"]]},{"id":"279508d1.f18468","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":470,"y":260,"wires":[]}]


(2) キーボードのLEDを点滅させる

 キーボードのScroll LockのLED(下の写真の赤丸)を点滅させてみます。あまり使う機会がないLEDなので、Node-REDからの通知のために使っちゃいましょう。

scrolllock2.png

※ Wikipediaの写真を使用

 Java functionノードにRobotクラスを用いてScroll Lockキーを押すコードを記載します。

scrolllock.png

 injectノードをクリックする度に、LEDがチカチカ点滅します。e-mailノードと合わせることで、メールが届いたことをLEDの点滅で知らせるフローも作れそうですね。


キーボードのLEDを点滅させるフロー

[{"id":"44c7ddf6.403c24","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":180,"y":480,"wires":[["e38dcfdf.cc86e"]]},{"id":"5a9065ca.2d930c","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":510,"y":480,"wires":[]},{"id":"e38dcfdf.cc86e","type":"javafunction","z":"3cd542b9.3985de","name":"blink scroll lock","func":"Robot rb = new Robot();\nrb.keyPress(KeyEvent.VK_SCROLL_LOCK);\nrb.keyRelease(KeyEvent.VK_SCROLL_LOCK);\nreturn msg;","outputs":1,"x":340,"y":480,"wires":[["5a9065ca.2d930c"]]}]


(3) 指定したURLをブラウザで開く

 URLが記載されたメッセージを受け取ると、ブラウザでページを開く処理もDesktopクラスを用いて記述できます。

browser.png

上のフローでは、デフォルトのブラウザをGoogle Chromeにしている場合、実行するとwww.google.co.jpをGoogle Chromeで開きます(フローエディタをGoogle Chromeで操作している場合、新規のタブで開きます)。

google.png

 パソコンを使う際、URLをコピーしてブラウザ上に貼り付けてページを開くという操作はよく行うと思います。後述するクリップボード連携機能と組み合わせれば、"http://"や"https://"で始まる文字列がクリップボードに保存されたタイミングで、一足早くブラウザを開く様な便利フローも書けますね。


指定したURLをブラウザで開くフロー

[{"id":"b5368af2.afcbc8","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"http://www.google.co.jp","payloadType":"str","repeat":"","crontab":"","once":false,"x":200,"y":380,"wires":[["272fb242.1067ee"]]},{"id":"272fb242.1067ee","type":"javafunction","z":"3cd542b9.3985de","name":"open browser","func":"URI uri = new URI(msg.get(\"payload\").getAsString());\nDesktop.getDesktop().browse(uri);\nreturn msg;","outputs":1,"x":400,"y":380,"wires":[["68407010.0f3ac"]]},{"id":"68407010.0f3ac","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":570,"y":380,"wires":[]}]


(4) クリップボードを読み書きする

 Java functionノードを用いると、クリップボードにアクセスもできます。下のフローでは、メッセージで受け取った文字列"data"をクリップボードへ保存し、別のフローでクリップボードの内容を呼び出しています。

write_read_clipboard.png

 Java functionノードでは、Clipboardクラスを用いてクリップボードの読み書きをしています。

write_clipboard.png

read_clipboard.png

 fileノードと組み合わせれば、クリップボードの履歴管理を行うフローも書けそうです。


クリップボードを読み書きするフロー

[{"id":"aee0f3ab.fadef","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"data","payloadType":"str","repeat":"","crontab":"","once":false,"x":110,"y":360,"wires":[["8c33e48c.c2cac8"]]},{"id":"8c33e48c.c2cac8","type":"javafunction","z":"3cd542b9.3985de","name":"save to clipboard","func":"String str = msg.get(\"payload\").getAsString();\nToolkit tk = Toolkit.getDefaultToolkit();\nClipboard cb = tk.getSystemClipboard();\ncb.setContents(new StringSelection(str), null);\nreturn msg;","outputs":1,"x":270,"y":360,"wires":[["ce731dd.2cdc4e"]]},{"id":"ce731dd.2cdc4e","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":450,"y":360,"wires":[]},{"id":"51b942a1.110d0c","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":120,"y":420,"wires":[["2e071160.2678ce"]]},{"id":"2e071160.2678ce","type":"javafunction","z":"3cd542b9.3985de","name":"read clipboard","func":"Toolkit tk = Toolkit.getDefaultToolkit();\nClipboard cb = tk.getSystemClipboard();\nObject oj = cb.getData(DataFlavor.stringFlavor);\nmsg.addProperty(\"payload\", oj.toString());\nreturn msg;","outputs":1,"x":280,"y":420,"wires":[["93c1a28a.e100a"]]},{"id":"93c1a28a.e100a","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":450,"y":420,"wires":[]}]


(5) マウスカーソルの位置を取得、変更する

 マウスカーソルの座標を取得したり、指定した座標にマウスカーソルを移動させることもできます。まず、マウスカーソルのX、Y座標を取得し、デバッグタブに表示してみます。

get_mouse_location2.png

 マウスカーソルの位置を取得するにはPointerInfoクラスを用います。定期的にinjectノードを実行するように設定し、マウスカーソルを移動すると、デバッグタブ上のX、Y座標の値が刻々と変化します。

get_mouse_location.png

次に、マウスカーソルを移動させるフローを書いてみます。

move_mouse2.png

 マウスカーソルを移動させるには、Robotクラスを用います。injectノードのボタンをクリックすると、指定した座標へマウスカーソルが飛びます。

move_mouse.png

 この仕組みを使えば、MQTT経由で受け取ったセンサの値を使ってマウスを操作することもできますね。面白マウスを簡単に開発できそうです。


マウスカーソルの位置を取得、変更するフロー

[{"id":"84d59034.87a96","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":120,"y":480,"wires":[["df3edce2.04cfa"]]},{"id":"df3edce2.04cfa","type":"javafunction","z":"3cd542b9.3985de","name":"get mouse location","func":"PointerInfo pi = MouseInfo.getPointerInfo();\nPoint pt = pi.getLocation();\nJsonObject jo = new JsonObject();\njo.addProperty(\"x\", pt.getX());\njo.addProperty(\"y\", pt.getY());\nmsg.add(\"payload\", jo);\nreturn msg;","outputs":1,"x":290,"y":480,"wires":[["3b3449cb.5889e6"]]},{"id":"3b3449cb.5889e6","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":470,"y":480,"wires":[]},{"id":"d80fd109.6c26f","type":"javafunction","z":"3cd542b9.3985de","name":"move mouse","func":"Robot rb = new Robot();\nJsonObject jo = (JsonObject)msg.get(\"payload\");\nint x = Integer.parseInt(jo.get(\"x\").toString());\nint y = Integer.parseInt(jo.get(\"y\").toString());\nrb.mouseMove(x, y);\nreturn msg;","outputs":1,"x":310,"y":540,"wires":[["d10b91b3.4141"]]},{"id":"888f6d50.e793f","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"{\"x\":245,\"y\":530}","payloadType":"json","repeat":"","crontab":"","once":false,"x":140,"y":540,"wires":[["d80fd109.6c26f"]]},{"id":"d10b91b3.4141","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":470,"y":540,"wires":[]}]


(6) ダイアログを表示する

 前のノードから受け取ったメッセージを含む確認ダイアログを表示してみます。下のスクリーンショットにあるウィンドウを表示させます。

dialog2.png

 ダイアログを表示するには、JOptionPaneクラスを用います。少し長いですが本質は3,4行目のみです。

dialog.png

Node-RED標準では、Twitterやe-mailノードなどオンラインのサービスでイベントを良く用いますが、スマホやメール通知の仕組みが必要です。確認ダイアログの方法は、Node-RED単体で使えるので便利です。


ダイアログを表示するフロー

[{"id":"80733fc8.a636b","type":"debug","z":"3cd542b9.3985de","name":"","active":true,"console":false,"complete":"false","x":490,"y":700,"wires":[]},{"id":"73578fbe.9ba63","type":"javafunction","z":"3cd542b9.3985de","name":"show dialog","func":"String lf = UIManager.getSystemLookAndFeelClassName();\nUIManager.setLookAndFeel(lf);\nString payload = msg.get(\"payload\").getAsString();\nJOptionPane op = new JOptionPane(payload,\n    JOptionPane.PLAIN_MESSAGE,\n    JOptionPane.DEFAULT_OPTION);\nJDialog dg = op.createDialog(null, null);\ndg.setAlwaysOnTop(true);\ndg.setVisible(true);\nreturn msg;","outputs":1,"x":330,"y":700,"wires":[["80733fc8.a636b"]]},{"id":"6467a0e7.53bfc","type":"inject","z":"3cd542b9.3985de","name":"","topic":"","payload":"message","payloadType":"str","repeat":"","crontab":"","once":false,"x":180,"y":700,"wires":[["73578fbe.9ba63"]]}]


Java functionノードのインストール方法

 今回紹介した例は、WindowsやMacにインストールしたNode-RED上で動作確認を行いました。Java functionノードを使えるようにするには、以下の3ステップを行います。詳細は各リンク先のドキュメントを参照し、インストールしてください。

(1) Java JDKをインストール

(2) java、javacコマンドが実行できるよう環境変数を設定

(3) Node-REDの「バレットの管理」から「node-red-contrib-java-function」をインストール


最後に

 Javaの標準ライブラリはとても充実しているため、今回紹介した例以外にも面白い使い道がありそうです。ぜひJava functionノードを使って遊んでみてください。