Node-RED+CloudFunctionsでPythonを動かす

# CloudFunctionsとは？

<img src="https://qiita-image-store.s3.amazonaws.com/0/237144/e3f7be55-2548-aed8-c67f-bc5af5f23fb4.png" width="100"> <img src="https://qiita-image-store.s3.amazonaws.com/0/237144/ddf8e0e2-f630-98f0-54a6-95cf5eb58f5b.png" width="100"> 

* Cloud上に関数を置ける
* httpリクエストで実行できる
* Node.js、Pythonに対応している

つまり**「Node-REDからhttpリクエストでCloudFunctionsにある関数を呼び出せばPythonが動くよ！」**と言うことです。
詳しくは[こちら](https://cloud.google.com/functions/docs/?hl=ja)を参照してください。

# 具体的な手順
※Google Cloud Platformの環境が整っている前提で書いていきます。

### CloudFunctionsに関数を追加する

ローカル環境のフォルダ構成は以下の通りです。
詳しくは[Python での依存関係の指定](https://cloud.google.com/functions/docs/writing/specifying-dependencies-python?hl=ja)を参照してください。
![local.png](https://qiita-image-store.s3.amazonaws.com/0/237144/8f40093c-8d68-ef95-dc50-d4073d5c4a25.png)


#### ローカル環境で関数を作る

例としてリクエストで受け取った文字を2つ繋げて返すだけの関数を作りました。
ファイル名は必ずmain.pyです。CloudFunctionsに追加する関数名=メイン関数(今回はhelloWorld)になります。

```
import sys

def helloWorld(request):
    """リクエストを編集して返す
    """
    import struct
    import json

    ret = ''

    #リクエストデータ(JSON)を変換
    request_json = request.get_json()
    #print(request_json)

    if request_json and 'data' in request_json:
        ret = request_json['data']
        ret += ret
        
    return ret
```

もし使いたいパッケージがあればrequirements.txtに記述します。
(例えばopencv-pythonやPillowなどなど)

#### デプロイする

こんな感じでバッチファイルを作っておくと便利です。

```
cd /d %~dp0\helloWorld
gcloud functions deploy helloWorld --runtime python37 --trigger-http --region asia-northeast1
```

これで無事追加されました。
![CloudFunctions_0.PNG](https://qiita-image-store.s3.amazonaws.com/0/237144/65220768-a965-43eb-6033-b3ed4afc552d.png)

関数を選択すると、トリガーとなるURLを確認できます。
![CloudFunctions_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/237144/1c0f4357-10f2-eb76-732f-06c06b68738f.png)


### Node-REDの設定

#### httpリクエストを使います。

![node-red_0.PNG](https://qiita-image-store.s3.amazonaws.com/0/237144/5bf57f9a-2580-14a4-a363-47165eb1c9ab.png)

リクエストは以下のようにしています。

```
msg.headers = {'content-type':'application/json'};
msg.payload ={
    "data" : "Hello World! "
}

return msg;
```

無事動きました。
![node-red_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/237144/9568f02a-36da-a59d-66bc-b13ac82a8d26.png)



フローはこちらです。

```
[{"id":"14e0b157.897c6f","type":"debug","z":"b229a692.0aace8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":670,"y":120,"wires":[]},{"id":"d8857efc.bfef3","type":"function","z":"b229a692.0aace8","name":"リクエスト生成","func":"msg.headers = {'content-type':'application/json'};\nmsg.payload ={\n    \"data\" : \"Hello World! \"\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":160,"wires":[["14e0b157.897c6f","4cb37902.60edd8"]]},{"id":"4cb37902.60edd8","type":"http request","z":"b229a692.0aace8","name":"","method":"POST","ret":"txt","url":"","tls":"","x":490,"y":160,"wires":[["cf8a4c8.66c55b"]]},{"id":"23f23570.64fefa","type":"inject","z":"b229a692.0aace8","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":160,"wires":[["d8857efc.bfef3"]]},{"id":"cf8a4c8.66c55b","type":"debug","z":"b229a692.0aace8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":670,"y":160,"wires":[]},{"id":"b3015520.0971e8","type":"comment","z":"b229a692.0aace8","name":"Pythonを動かす","info":"","x":120,"y":100,"wires":[]}]
```

## まとめ
ネットワークに接続できる環境であれば、デプロイする装置(ラズパイなど)に依存しないメリットがあります。

何か参考になれば嬉しいです。ではでは。