外部トリガーからカメラを起動してTeachable Machineに繋げてみる 


Node-REDからTeachable Machine（以下、TM）を使う時に[node-red-contrib-browser-utils](https://flows.nodered.org/node/node-red-contrib-browser-utils)のカメラで写真を撮影してを使うのが一般的？です。

## カメラボタン以外から起動させたい

このやり方だとカメラボタン以外からの起動ができず、外部のスイッチを押して起動、何かLINEが届いたらカメラ起動など外部トリガーからの起動ができません。

> ![](https://i.gyazo.com/f6915251699613d95e424ed0ce8cf77b.png)

[@sumit_shinde_84/node-red-dashboard-2-ui-webcam](https://flows.nodered.org/node/@sumit_shinde_84/node-red-dashboard-2-ui-webcam)というノードを使うことで外部トリガーからカメラ起動ができます。

> こちらのノードは入力の口があるので外部トリガーから起動できます。
> ![](https://i.gyazo.com/9e3336c099cab6149eabf78b02f59e92.png)

## Base64からバイナリに変換が必要

そのまま使えたらシンプルだったのですが、従来使っていた`node-red-contrib-browser-utils`と今回利用したい`@sumit_shinde_84/node-red-dashboard-2-ui-webcam`はカメラ撮影後のデータの出力形式がBase64とバイナリで異なります。

[Teachable Machineノード](https://flows.nodered.org/node/node-red-contrib-teachable-machine)を使いたいですが、このノードはバイナリ形式でデータを受け付けるため変換が必要になります。

変換後はこんな感じです。

> ![スクリーンショット 2024-05-22 2.15.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/3d6c463e-681b-421c-5309-5aacd07088c9.png "スクリーンショット 2024-05-22 2.15.27.png")

このフローをそのまま使いたい方はこちらを利用してください。

```json
[{"id":"0a449bbcc199773e","type":"teachable machine","z":"938d0e1e97d89191","name":"","mode":"online","modelUri":"https://teachablemachine.withgoogle.com/models/9F0TKnYG0/","localModel":"teachable_model","output":"best","activeThreshold":false,"threshold":80,"activeMaxResults":false,"maxResults":3,"passThrough":false,"x":570,"y":280,"wires":[["e8c3975c5b387ff1"]]},{"id":"4bb557d0f95efa41","type":"base64","z":"938d0e1e97d89191","name":"","action":"","property":"payload","x":420,"y":220,"wires":[["0a449bbcc199773e"]]},{"id":"e8c3975c5b387ff1","type":"debug","z":"938d0e1e97d89191","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":340,"wires":[]},{"id":"ac35941b9886834d","type":"switch","z":"938d0e1e97d89191","name":"","property":"payload","propertyType":"msg","rules":[{"t":"neq","v":"data:image/png;base64","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":390,"y":160,"wires":[["4bb557d0f95efa41"]]},{"id":"72b5d05f2d5064a8","type":"split","z":"938d0e1e97d89191","name":"","splt":",","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","property":"payload","x":370,"y":100,"wires":[["ac35941b9886834d"]]},{"id":"520ddd626ebbebf3","type":"ui-webcam","z":"938d0e1e97d89191","name":"","group":"fc1505d2ec1d5ec1","width":0,"height":0,"passthru":false,"x":250,"y":60,"wires":[["d6929a6b525f0c97","72b5d05f2d5064a8"]]},{"id":"1fb94131a97b384f","type":"inject","z":"938d0e1e97d89191","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"capture","payloadType":"str","x":90,"y":40,"wires":[["520ddd626ebbebf3"]]},{"id":"d6929a6b525f0c97","type":"image","z":"938d0e1e97d89191","name":"","width":160,"data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":false,"outputs":0,"x":640,"y":60,"wires":[]},{"id":"fc1505d2ec1d5ec1","type":"ui-group","name":"My Group","page":"27acc56fb36e7279","width":6,"height":1,"order":-1,"showTitle":true,"className":"","visible":true,"disabled":false},{"id":"27acc56fb36e7279","type":"ui-page","name":"Page 1","ui":"8552fcf0db16fa83","path":"/page1","icon":"home","layout":"grid","theme":"96c650faab345d8b","order":1,"className":"","visible":"true","disabled":"false"},{"id":"8552fcf0db16fa83","type":"ui-base","name":"My Dashboard","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"navigationStyle":"default"},{"id":"96c650faab345d8b","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#0094CE","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]
```

## 変換手順

まずはTMノード側はバイナリ形式で受けないといけないので、Base64から変換する必要があります。

> ![](https://i.gyazo.com/b0599a949958f0b526affcd214eda796.png)

[node-red-node-base64](https://flows.nodered.org/node/node-red-node-base64)を使うとBase64とバイナリを相互変換できるので便利です。

ただ、ui-webcamノードからは`"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAA...`といった文字列で送られてきます。

これはプレフィックスの`data:image/png;base64,`の部分が邪魔になりうまく変換できません。`,`以降の`iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAA...`の部分を抽出してBase64変換の`node-red-node-base64`に渡す必要があります。

そこで間に`splitノード`と`changeノード`を挟みます。

- splitノード

splitノードで`,`の前後で分割します。

> ![スクリーンショット 2024-05-22 12.36.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/2d542c69-bdeb-3d60-2dc5-832e602cc9e1.png "スクリーンショット 2024-05-22 12.36.48.png")

- changeノード

changeノードで`data:image/png;base64,`の部分は次のノードに渡さないようにフィルターします。

> ![スクリーンショット 2024-05-22 12.37.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/b398f767-7aa0-e6ef-1aa5-33b6dd60e922.png "スクリーンショット 2024-05-22 12.37.23.png")


この設定をした上でBase64変換がやっとできました。

> ![](https://i.gyazo.com/076736c116e0c7130e3a0f235d2b6a1c.png)

## ui-webcamの注意

そういえばui-webcamはダッシュボード側でカメラを表示させてないとONになってくれなかったです。

https://hogehoge.com/dashboard

という形でdashboardにアクセスして別タブでカメラを起動した状態で利用しましょう。

## まとめと所感

ちょっと一手間ありますが、これで無事に外部トリガーからカメラが起動できます。

Teachable MachineノードがBase64対応してくれたら楽なのでプルリク出してみようかな...