おつまみディスペンサーを IoT 化してみた。

"お酒" には "おつまみ" が付きものということで、今回はタッチセンサー付きおつまみディスペンサーを IoT 化してみた。

🍶 🍺 🍻 🍷 🍸 🍹 🍾 🥃　＋　🍲 🍔 🌭 🌮 🌯 🍕 🍖 🍗 🍙 🍛 🍜 🍝 🍢 🍣 🍚

キャンディ・ディスペンサーとか、おつまみディスペンサーとか、オートディスペンサーなどの検索キーワードで出てくる製品で、以下２つの製品を入手して分解したところ同じ基盤・部品・配線で実装されていたので、同じ仕組みでイケると思う。

<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/c1ff1b77-1623-f5fc-a08a-4df39cb4d16d.png" width=50%><img src="https://qiita-image-store.s3.amazonaws.com/0/72479/46018873-3130-5481-0b44-d6648a9666c3.png" width=40%>

## 構成
スマートスピーカー (Google Home または Amazon Alexa) を入力として、Node-RED を経由して webhook リクエストを MQTT リクエスト (Publish) へ変換し、Milkcocoa 経由でおつまみディスペンサーへ MQTT リクエスト (Subscribe) を送る構成とした。音声入力の内容によって Node-RED からの MQTT リクエストの内容を変更して、おつまみディスペンサーへのリクエストを振り分ける構成とした。

![スクリーンショット 2018-04-11 10.43.49.png](https://qiita-image-store.s3.amazonaws.com/0/72479/34cc7a40-8b1a-72d7-d210-8c1f77f155d7.png)

## 分解
本製品は中身 (おつまみ) を入れ替えるので基本的に分解して洗えるようになっている。

![取扱説明書.png](https://qiita-image-store.s3.amazonaws.com/0/72479/31f197ba-ce11-012e-96f7-0f11f9b9f808.png)

ケース、トレイ、回転体を取り外し、３本のネジをプラスドライバーで外すと基盤、モーター、タッチセンサーへアクセスできる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/d97fa1ba-74c1-31f4-a19b-a334367442fa.png" width=50%>
<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/9e6623ca-1032-c02a-ba0f-57d015f52f59.png" width=80%>

台座は裏面の滑り止め (スポンジ) を取り外すと４本のネジが現れ、プラスドライバーで外すと電池ボックス、スライドスイッチへアクセスできる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/754f2ba2-be23-920a-93a1-e8370d842a84.png" width=50%><img src="https://qiita-image-store.s3.amazonaws.com/0/72479/241f8fda-d351-874b-5022-23dfcc6bf5b5.png" width=50%>
<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/0dcccf43-c791-8e2e-e601-7cfe86517076.png" width=50%><img src="https://qiita-image-store.s3.amazonaws.com/0/72479/5c4ee0ef-2bc5-d658-3a54-982d6a230dfa.png" width=50%>

## 配線図
基盤に搭載されているシングルチャネルタッチセンサースイッチのチップの仕様は<A HREF="http://www.rhme.net/products/rh6015.htm">こちら</A>。(<A HREF="http://www.baitaishengshi.com/uploadfile/2016/0807/20160807140411.pdf">仕様書</A>)
既存のタッチセンサー機能を活かしつつ、リモート操作が可能となるよう、Wio-Node で MOS-FET のゲート電圧を操作することでモーターの陰極 (−) をスイッチングさせる配線とした。MOS-FETは定番の 2SK2232(60V25A) の入手が困難となったため、代替品として 2SK4017(60V5A)　または 2SK703(100V5A) を使用した。
また、Wio-Node の電源は既存の電源ボックスから供給し、スライドスイッチで ON/OFF できる配線とした。

![スクリーンショット 2018-04-12 11.35.22.png](https://qiita-image-store.s3.amazonaws.com/0/72479/2471ea7a-0d03-5db5-134f-be1c9d60b424.png)

中蓋を取り外したあと、基盤 (基盤を止めているネジ付近) へ１本リード線をハンダ付けし、脚筒を通して台座の裏面へ配線する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/7ee37940-5d6a-bdfe-af7b-049ce919b5da.png" width=40%>
<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/011895b2-dc33-27e3-fe17-06a1b454875b.png" width=80%>

・モーターの陰極 (−) を制御するため基盤へハンダ付けし台座の裏面へ配線したリード線を MOS-FET (ドレイン) へ接続し、電池ボックスの陰極 (−) から MOS-EFT (ソース) へ接続し、Groveコネクタ (黄色のリード線) を抵抗 (220Ω) を挟んで MOS-FET (ゲート) へ接続する。
Wio-Node へ電源供給するための PH2 コネクタの陰極 (−) を電池ボックスへ、陽極 (＋) をスライドスイッチへ接続する。

<img src="https://qiita-image-store.s3.amazonaws.com/0/72479/5da9ead1-1afd-7128-6313-d2b0b0111eaf.jpeg" width=80%>

## ソースコード
Wio-Nodeのソースコードは<A HREF="https://github.com/kitazaki/ESP8266_otsumami_dispenser/blob/master/ESP8266_MOTOR.ino">こちら</A>。

```c:ESP8266_MOTOR_01.ino
#include <ESP8266WiFi.h>
#include <Milkcocoa.h>

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

#define MOTORPIN 5 // Wio-Node IO5 => MOTOR,  NodeMCU D1=GPIO5 D6=GPIO12
#define DEVICEID 1 // if selector is 0, MOTOR works in 0.1 second for health check purpose. 
                   // if selector is DEVICEID, MOTOR is switched on during timer. if NOT, MOTOR doesn't work.

WiFiClient client;

#define MILKCOCOA_APP_ID    ""  // MilkCocoa Application ID
#define MILKCOCOA_DATASTORE ""  // MilkCocoa Datastore Name
#define MILKCOCOA_SERVERPORT  1883

const char MQTT_SERVER[] PROGMEM    = MILKCOCOA_APP_ID ".mlkcca.com";
const char MQTT_CLIENTID[] PROGMEM  = __TIME__ MILKCOCOA_APP_ID;

Milkcocoa milkcocoa = Milkcocoa(&client, MQTT_SERVER, MILKCOCOA_SERVERPORT, MILKCOCOA_APP_ID, MQTT_CLIENTID);

int red, green, blue, selector, timer;

void onpush(DataElement *elem) {
  Serial.println("onpush");
  Serial.print("r:");
  Serial.print(elem->getInt("r"));
  Serial.print(",g:");
  Serial.print(elem->getInt("g"));
  Serial.print(",b:");
  Serial.print(elem->getInt("b"));
  Serial.print(",s:");
  Serial.print(elem->getInt("s"));
  Serial.print(",t:");
  Serial.print(elem->getInt("t"));
  Serial.println();

  red = elem->getInt("r");
  green = elem->getInt("g");
  blue = elem->getInt("b");
  selector = elem->getInt("s");
  timer = elem->getInt("t");

  if (selector) {
    if (selector == DEVICEID) {
      digitalWrite(MOTORPIN, HIGH); 
      delay(timer * 1000);
      digitalWrite(MOTORPIN, LOW); 
    }
  } else {
    digitalWrite(MOTORPIN, HIGH); 
    delay(100);
    digitalWrite(MOTORPIN, LOW); 
  }
}

void setupWiFi() {
  Serial.println(); 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();
  Serial.println( milkcocoa.on(MILKCOCOA_DATASTORE, "push", onpush) );
  pinMode(MOTORPIN, OUTPUT); 
}

void loop() {
  milkcocoa.loop();
}
```

## まとめ
現在構想中の IoT 居酒屋 (仮) の実現に向けて一歩でも近づければ幸いです。

[![スクリーンショット 2018-04-12 13.35.17.png](https://qiita-image-store.s3.amazonaws.com/0/72479/7251ac53-d512-c72a-38df-9e7d41943e92.png)](https://youtu.be/m-trLhURs2Q)