ESP8266でTouchDesigner099のMQTT Client DATを試してみた。

![LogosDerivative.5.jpg](https://qiita-image-store.s3.amazonaws.com/0/72479/6e279cd0-0c3c-f809-8cdf-7057bb5f64ea.jpeg)
![スクリーンショット 2018-04-02 17.20.40.png](https://qiita-image-store.s3.amazonaws.com/0/72479/98c487ca-8277-23d2-5ffd-c23c09b54da2.png)

IoT 界隈ではおなじみの MQTT プロトコルが TouchDesigner099 からサポートされ、<A HREF="https://www.derivative.ca/wiki099/index.php?title=MQTT_Client_DAT">MQTT Client DAT</A> の機能が追加されたのでさっそく試してみた。

試してみるのにあたり、<A HREF="https://infusionsystems.com/pishield/pishield-touchdesigner-via-mqtt/">こちら</A> のサイトが大変参考になった。
TouchDesigner を操作するインターフェイスはボリューム抵抗とスライド抵抗で、Raspberry Pi に mcp3008 (10bit 8ch ADコンバータ) を SPI 接続し、mcp3008 にボリューム抵抗とスライド抵抗を接続し、Node-RED (npm コマンドで mcp3008 ノードを追加) で mcp3008 のデータ値 (厳密には mcp3008 に接続された抵抗に掛かる電圧値) を読み出して MQTT Broker へ送信 (Publish) する実装例であった。

今回は操作するインターフェイスをボリューム抵抗のみとし、ESP8266 を使用して実装を行うこととした。

# 接続構成・配線図
ESP8266 に接続されたボリューム抵抗を回すと MQTT Broker 経由で TouchDesigner へ値が入力される構成とした。

![スクリーンショット 2018-04-02 17.13.02.png](https://qiita-image-store.s3.amazonaws.com/0/72479/b693ec1e-10df-6a0f-1497-c8c4ade6540b.png)

### ESP8266 (MQTT Publish)
ESP8266 で AD 変換をする方法については <A HREF="https://qiita.com/azusa9/items/26e74e4e0d5773ce9c41">こちら</A> を参考にした。

![スクリーンショット 2018-04-02 17.44.48.png](https://qiita-image-store.s3.amazonaws.com/0/72479/f6fe4c01-3bb0-68b6-1c07-7ff25ccd6418.png)

A0 ピン (TOUT ピン) を使った AD 変換は、0.0V ～ 1.0V の範囲で 10 bit の分解能を持って計測する事ができるとのこと。
上記のように抵抗 (5KΩ, 10KΩ, B10KΩ) を配線し、ボリューム抵抗を回すと0.6V 〜 1.0V の範囲で電圧が変化することをテスターで確認できた ( ESP8266 で 207 〜 334 の範囲で値が変化することを確認できた) ため、これを -0.5 〜 0.5 の範囲へ値を正規化して MQTT Broker へ入力することとした。

### MQTT Broker
MQTT Broker を導入する方法については <A HREF="https://qiita.com/segur/items/0536ced1fe741b55713d">こちら</A> を参考にした。
今回は Mac へ Homebrew を使って Mosquitto をインストールした。

起動

```bash
$ mosquitto

1522681098: mosquitto version 1.4.14 (build date 2017-10-22 16:34:22+0100) starting
1522681098: Using default config.
1522681098: Opening ipv6 listen socket on port 1883.
1522681098: Opening ipv4 listen socket on port 1883.
```

ESP8266 または TouchDesigner から接続されるとログが出力される。

```bash
1522681155: New connection from 172.30.16.177 on port 1883.
1522681155: New client connected from 172.30.16.177 as ESP8266_Client (c1, k30).

1522664940: New connection from 172.30.16.178 on port 1883.
1522664940: New client connected from 172.30.16.178 as TD_76858_4338_19 (c1, k50).
```

### MQTT Publish (接続試験)

```bash
$ mosquitto_pub -h 172.30.16.179 -t "/pishield/chan6" -m "0.1" -q 0

$ mosquitto_pub -h 172.30.16.179 -t "/pishield/chan7" -m "0.2" -q 0
```

### MQTT Subscribe (接続試験)

```bash
$ mosquitto_sub -h 172.30.16.179 -t "/pishield/chan6" -q 0
0.1

$ mosquitto_sub -h 172.30.16.179 -t "/pishield/chan7" -q 0
0.2
```

### TouchDesigner099 (MQTT Subscribe)
TouchDesigner099 のダウンロードは <A HREF="https://www.derivative.ca/099/Downloads/">こちら</A> 。
TouchDesigner のインストール方法、基本的な操作方法については <A HREF="https://www.shuhei-matsuyama.com/single-post/2015/12/17/TouchDesigner%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%96%B9%E6%B3%95">こちら</A> が大変参考になった。

OP Create ダイアログボックスの DAT Operator タブの中から MQTT Client を選択する。
![スクリーンショット 2018-04-03 16.03.26.png](https://qiita-image-store.s3.amazonaws.com/0/72479/d29b0930-0ee5-de04-5d73-3d4413512840.png)

MQTT Client Operator のパラメータウィンドウで Connect -> Network Address に MQTT Broker の IP アドレスを設定する。
![スクリーンショット 2018-04-02 19.31.45.png](https://qiita-image-store.s3.amazonaws.com/0/72479/1c5f6a71-2589-a01a-926a-a5d1e1ef6436.png)

MQTT Client Operator の callbacks の内容 (Python script) はこちら。

```python
# me - this DAT
# 
# dat - the OP which is cooking
# topic - topic name of the incomming message
# payload - payload of the incomming message
# qos - qos flag for of the incomming message
# retained - retained flag of the incomming message
# dup - dup flag of the incomming message

# reference the MQTT Client DAT
a = op('/project1/mqttclient1')
t = op('/project1/table1') 
 
# subscribe to the temp/random topic
a.subscribe('/pishield/chan6',qos=0)
a.subscribe('/pishield/chan7',qos=0)

def onConnect(dat):
	return

def onConnectFailure(dat):
	return

def onConnLost(dat):
	return

def onSubscribe(dat):
	print('subscribed!', dat)
	return

def onSubscribeFailure(dat):
	return

def onUnsubscribe(dat):
	return

def onUnsubscribeFailure(dat):
	return

def onPublish(dat):
	return

def onMessage(dat, topic, payload, qos, retained, dup):
	print('received message ', payload)
	if (topic == '/pishield/chan6'):
		t[6,0] = float(payload)
	if (topic == '/pishield/chan7'):
		t[7,0] = float(payload)
	return
```

# ソースコード
TouchDesigner のサンプルファイルは <A HREF="https://github.com/kitazaki/TouchDesigner_MQTT_Client_DAT/blob/master/MQTT_test_01.toe">こちら</A> 。

ESP8266 のサンプルコードは <A HREF="https://github.com/kitazaki/TouchDesigner_MQTT_Client_DAT/blob/master/ESP8266_ADC_01.ino">こちら</A> 。

```c:ESP8266_ADC_01.ino
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

extern "C" {
  #include "user_interface.h"
}

#define WLAN_SSID       ""  // Wi-Fi SSID
#define WLAN_PASS       ""  // Wi-Fi Password

// const char *mqtt_host = "";  // MQTT Host
byte ip[] = {172, 30, 16, 179};  // MQTT IP Address
const char *mqtt_topic = "/pishield/chan6"; // MQTT Topic (chan6 = rotation)
// const char *mqtt_topic = "/pishield/chan7"; // MQTT Topic (chan7 = horizontal move)

// ClientID
const char *mqtt_client = "ESP8266_MQTT_Client";

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
}

WiFiClient wclient;
// PubSubClient client(mqtt_host, 1883, callback, wclient);  // MQTT Host
PubSubClient client(ip, 1883, callback, wclient);  // MQTT IP Address

void setupWiFi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);
  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void setup() {
  pinMode(15, OUTPUT);  // for Wio-Node
  digitalWrite(15, 1);  // for Wio-Node
  Serial.begin(115200);
  setupWiFi();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    setupWiFi();
  }
  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      Serial.println("Connecting to MQTT server");
      if (client.connect(mqtt_client)) {
        Serial.println("Connected to MQTT server");
      } else {
        Serial.println("Could not connect to MQTT server");
      }
    }
    Serial.print("Publishing: ");
    int value = system_adc_read();
    Serial.println("Value: " + String(value));
    // normalize: Y = (X - Xmin) / (Xmax - Xmin) => 0 - 1
    float f = (float(value) - 207) / (334 - 207) - 0.5;
    // cast float => char
    char s[8];
    dtostrf(f, 2, 5, s);
    Serial.println("Value: " + String(value) + ", " + s);
    client.publish(mqtt_topic, s);
    if (client.connected()) {
      client.loop();
    }
  }
  delay(100);
}
```

# まとめ
身近な IoT デバイスと TouchDesigner が組み合わさることによってノード系ビジュアルプログラミングの "よさみ" が深くなれば幸いです。

[![スクリーンショット 2018-04-02 17.18.01.png](https://qiita-image-store.s3.amazonaws.com/0/72479/c2199360-6f2b-a73a-ee86-550f6cde7c55.png)](https://youtu.be/vSbWjytm5zk)