展示やイベントでTouchDesignerを使う際のTIPS

展示やイベントなどでTouchDesignerを使う際に、
ここらへんの設定をしておくと便利だよ。という内容は、各々が秘伝のタレとして持っていると思うのですが、あまり記事としてはまとまってないような気もしたので、僕の中でこれは便利かもと思った項目を書き出してみました。

もしこれを見た方で、こうゆうのもあるよ！などあれば気軽に教えて貰えたら嬉しいです。
それと今回は主にWindows10を対象に書いていますので、Macの方は適宜読み替えつつご覧頂ければと思います。

※免責とまでは言わないのですが、環境によってはうまく動作しなかったりする可能性もあるので確認・テストは各自できちんと行ってください。:pray:


# 目次

- 0. [マシン側の事前準備](#0-マシン側の事前準備)
- 1. [TDのプロジェクトを自動立ち上げ＆死活監視](#1-tdのプロジェクトを自動立ち上げ死活監視)
    - 1-1. [監視用exeをPythonで作る](#1-1-監視用exeをpythonで作る)
    - 1-2. [Restart on Crashに登録する](#1-2-restart-on-crashに登録する)
- 2. [Production/Developでパラメータを変更する](#2-productiondevelopでパラメータを変更する)
- 3. [WebhookでSlackに状態を送る](#3-webhookでslackに状態を送る)
    - 3-1. [Slackでアプリを作成](#3-1-slackでアプリを作成)
    - 3-2. [Webhookを送る](#3-2-webhookを送る)

上記1,2,3のテストファイルは下記のリポジトリに`.toe`などが入っているので、参考にしてみてください。
https://github.com/hisahayashi/TD_Exhibition_Template/

# 0. マシン側の事前準備
まず現場でマシンを動かす前に各種設定を行っておきます。
こちらの記事に現場機で行うべき設定などは全てまとまってるので、一通り見てみると良い気がします。
https://github.com/laserpilot/Installation_Up_4evr#tldr-quick-checklist



### TL; DRクイックチェックリスト（システム環境設定）

#### 推奨：
- スクリーンセーバーを「しない」に設定する
- 自動ソフトウェア更新を無効にする
- コンピューターとディスプレイのスリープを「しない」に設定する
- デスクトップの背景を黒一色に設定
- 「自動ログインを無効にする」のチェックを外します
- 利用するユーザーの自動ログインを有効にする

#### オプション：
- 画面共有とファイル共有を有効にする
- Bluetoothセットアップアシスタントを無効にする
- 通知センターを無効にする/サイレントモードを24時間に設定する

あとは、リモートアクセスの設定や再起動のスケジュール設定などを行っておきます。
[Windows10を指定時刻にシャットダウン／再起動する方法](https://4thsight.xyz/11488)

# 1. TDのプロジェクトを自動立ち上げ＆死活監視

営業時間中常にプロジェクトを起動していたい場合は、下記の動作を行う必要があるかと思います。

- **PC起動後すぐにTDのプロジェクトファイルを起動**
- **クラッシュ時にTDのプロジェクトファイルを再起動**

これらを行う際によく使うツールが「[Restart on Crash](https://www.softpedia.com/get/System/File-Management/Restart-on-Crash.shtml)」です。（Windowsのみ）
これはアプリの死活監視をして起動していなかった場合に自動で起動してくれるのと、クラッシュ時に所定の時間が経過したらアプリを再起動してくれるというツールです。

ただし、対象にできるアプリは`.exe`などの単独実行ファイルのみで、TouchDesignerの`.toe`ファイルはツールに登録することができません。
なので、監視用に簡易的な`.exe`を作成します。

## 1-1. 監視用exeをPythonで作る

ということで、TDのプロジェクトファイルを監視する用の`.exe`を作成します。
pythonをインストールし、プロジェクトファイルと同じ階層に`runtoe.py`を作成します。（Pythonのバージョンは3.7.6で確認しています）

```python:runtoe.py
import subprocess
import psutil

dict_pids = {
    p.info['pid']: p.info['name']
    for p in psutil.process_iter(attrs=['pid', 'name'])
}

if 'TouchDesigner.exe' in dict_pids.values():
	# print('Run TouchDesigner.')
	pass
else:
	# print('Stop TouchDesigner.')
	filepath = r'./[TOEファイルのパス].toe'
	subprocess.Popen(['start', filepath], shell=True)
	# print('Restarted TouchDesigner.')
```

次に Pyinstallerを使って上記の`.py`を実行ファイルとして書き出します。

```
$ pip install pyinstaller
$ python runtd.py
```

`8661 INFO: Building EXE from EXE-00.toc completed successfully.`
と出たら成功です。

するとdistフォルダに`runtoe.exe`が出来上がるので、これを一つ上の階層に移動して実行します。
上で指定した`.toe`が開き、開いた後に実行しても開かない、という動作をしたらOKです。


## 1-2. Restart on Crashに登録する

上で作成した`runtoe.exe`をRestart on Crashに登録します。
このときに、Restart on CrashをProgram Filesなどに置くと、セキュリティの関係でうまく動かないので、デスクトップなどに置いておくと良いと思います。

![Inkedスクリーンショット 2020-12-21 145702_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/5b3c0a1f-35ea-9613-3f37-b083ab516fa9.jpeg)
Addを押して設定を追加します。

![スクリーンショット 2020-12-21 150129.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/cae3cde3-f007-be22-d195-a86400df454c.jpeg)
モニタリングするアプリとクラッシュした後に実行するコマンドを実行する箇所に先程のexeを登録します。
また、ワーキングディレクトリは念の為、exeを置いている場所を設定します。

![スクリーンショット 2020-12-21 150348.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/64039f15-ef52-a774-18fe-e300c8e9011c.jpeg)
これで、toeファイルが自動で立ち上がるようになれば Restart on Crash での設定は完了です。

最後にRestart on Crash自体を**Windowsのスタートアップに追加**すれば、マシンの起動中は常に所定のtoeファイルが起動する仕組みが完成します。


# 2. Production/Developでパラメータを変更する

これは地味にめんどくさいけど最初にやっておくと後々便利な設定なのですが、
プロジェクトファイルと同階層とかにJSONを置いておき、それをリポジトリの監視から外しつつ起動時に読み込むようにしておくと現場PCと開発PCとでパラメータを変えた状態で開発が行えるので結構便利です。
こうしておくことで、デバッグ機能のON/OFFや解像度の変更などを変え忘れるミスなどが減ります。

具体的には下図のように、`Execute DAT`のStartフラグをOnにして、起動時にJSONを読み込み`Table DAT`に書き出す処理を実行しているだけです。

![スクリーンショット 2020-12-21 153212.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/cfc69119-c0ca-8b16-c6ef-8149db2c4a94.jpeg)

- execute1: Execute DAT
- load_setting: Text DAT
- config: Table DAT

```python:execute1
...

def onStart():
	op('load_setting').run()
	return

...
```

```python:load_settting
import json

json_file = 'setting.json'
json_open = open(json_file, 'r')
json_data = json.load(json_open)

op('config').clear()

# update table
for key, val in json_data['config'].items():
	op('config').appendRow([key, val])
```

あとは値を見つつお好きな処理をどうぞ！


# 3. WebhookでSlackに状態を送る

特に納品したてやテスト期間中の現場機の状態って気になりますよね？
そういった時にWebhookでSlackに今のマシンやアプリの状態を送ってあげると心の安定が保てます。

## 3-1. Slackでアプリを作成
まずは https://api.slack.com/apps/new にアクセスをして、「Create New App」からアプリを作成します。

![スクリーンショット 2020-12-21 155654.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/5f7d66b4-0531-1976-c5fd-d1f2b4606479.jpeg)
追加したいワークスペースを選択して「Create App」を押します。

![スクリーンショット 2020-12-21 155928.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/269a5493-e58a-42d6-93d2-4b07ac4c346f.jpeg)
「Incoming Webhooks」を押します。

![スクリーンショット 2020-12-21 155948.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/a70f23e6-3f9d-62fe-271f-eaa3f4976479.jpeg)
ActivateをOnにします。

![スクリーンショット 2020-12-21 160013.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/23f41353-be55-4ad1-02bc-ba974be934df.jpeg)
すると、Webhookが追加できるようになるので、「Add New Webhook to Workspace」を押します。


![スクリーンショット 2020-12-21 155852.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/15a176a3-561b-6810-acdd-8e803068b9dc.jpeg)
チャンネルを選択して「Allow」します。


![スクリーンショット 2020-12-21 160509.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/024f778e-d594-593b-72fb-56b3679a0428.jpeg)
すると、Webhook URLが生成されるので、Touch DesignerでこのURLを使いPOSTします。

## 3-2. Webhookを送る

この図のようにオペレータを組みます。
![スクリーンショット 2020-12-21 164442.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/afedf7fc-d5e7-04bf-096e-3b07a5f909e9.jpeg)

- sender: Text DAT
- webhok: Text DAT
- webclient1: Web Client DAT **（Mthod: GET）**


```python:sender
import webhook

post_webhook.Send("Touch Designer")
```

```python:webhook
import socket
import requests

host = socket.gethostname()
local_ip = socket.gethostbyname(host)
url = 'https://hooks.slack.com/services/xxxx/yyyy/zzzz'

def Send(message):
	clientOp = op('webclient1')
	header = {'Content-type': 'application/json'}
	data = {
		'text': '['+str(local_ip)+'] ' + str(message),
		# 'attachments': [{
		# 	'fields': [
		# 		{
		# 			'title': '',
		# 			'value': '',
		# 		}],
		# 	'image_url': ''
		# }]
	}
	clientOp.request(url, 'POST', header=header, data=str(data))
```
**6行目のurlを前項で作成したWebhookのURLに置き換えます。**

そして、senderを実行すると、下記のような感じでSlackにメッセージが投稿されます。
Perfome CHOPなどでマシンの状態を送って置くと、異常状態のデバッグなどに役立つかもしれません。
![スクリーンショット 2020-12-21 160619.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36929/36349685-a7d9-bf40-9129-eeb42a37af3f.jpeg)



---

要素が多くなってしまいましたが、少しでも参考になれば幸いです。
それでは良いTouch Designerライフを！