# 第13週- IoT 無線遠距控制
###### tags: `Bluetooth` `BLE` `IoT` `遠距控制`
終於到了遙控 ESP32 IoT 的課程,可以開始遠距讀取並控制 ESP32 的數值和動作。
## 遠距控制的方式:
**1) 紅外線** [(第12週課程)](https://hackmd.io/@smile2307/H1AzS7he3)
* ESP32 至少需加裝 1838B 紅外線發射接收器
* 傳輸速度與距離成反比,最快 16Mbps
* 工作功率極低,但容易被阻擋
* 較便宜
* 需額外的紅外線遙控器

**2) 藍牙**(第13週課程)
* ESP32 已內含BLE硬體,並具有天線
* 傳輸頻寬為 1Mbps
* 工作功率低,但ISM頻段 2.4GHz 容易受干擾
* 較貴
* 需藍牙連線的控制設備,如手機當 host 並配對

**3) WiFi網路**(第14、15週課程)
* ESP32 已內含WiFi硬體,並具有天線
* 傳輸頻寬為 1-11Mbps(2.4GHz)/1-500Mbps(5GHz)
* 工作功率較高,使用 ISM 頻段中的 2.4G/5GHz 雙頻
* 較貴
* 可以當成是工作站或熱點、或兩者同時,構成 IoT 普通採用的行動隨意網路 (MANET, Mobile ad‐hoc network) 或無線隨意網路 (WANET, Wireless ad‐hoc network)
* 可以證書方式認證並加密

## ESP32 藍牙實作:
### 實作一:
啟動 ESP32 藍牙功能
>1. 依課本 p.86 的硬體需求
>1. 依課本 p.87,上傳程式
>1. 需一部 Android 手機,並下戴安裝 "Arduino Bluetooth Control"
>1. Android 手機需先開藍牙設定、開啟、配對新裝置
>1. 依 p.89 所示,連接 ESP32 藍牙裝置
:::warning
hint: BluetoothSerial 宣告為 BT,BT.begin() 和 BT.println()
:::spoiler
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;//宣告藍芽物件,名稱為BT
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
}
void loop() {
BT.println("Hello World!");
delay(1000);
}
```
:::
:::success
觀察:當打開 App terminal 後,連續收到 "Hello World"。
:::
### 實作二::wink:延伸整合題
ESP32 透過藍牙將溫濕度數值,向手機傳送
>1. 增加 DHT11 硬體,訊號線接 GPIO 4
>1. 依課本 p.91,上傳程式
>1. App 連接 ESP32 藍牙裝置
:::warning
hint: 將 DHT11 練習的 Serial.println() 改為 BT.println()
:::spoiler
```javascript=
#include <SimpleDHT.h>
#include <BluetoothSerial.h>
BluetoothSerial BT;
int pinDHT11 = 4; //本例請將溫度計S腳接在GPIO 4
SimpleDHT11 dht11(pinDHT11);
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
}
void loop() {
// start working...
Serial.println("=================================");
Serial.println("Sample DHT11...");
// read without samples.
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT11 failed, err="); Serial.println(err); delay(1000);
return;
}
//將溫濕度傳輸到藍芽裝置
BT.print((int)temperature);
BT.print(" *C,");
BT.print((int)humidity);
BT.println(" H");
delay(1000); //休息1秒
}
```
:::
:::success
觀察:當打開 App terminal 後,連續收到溫濕度數值。
:::
:::info
已經擺脫 LCD 液晶顯示幕,可以遠距觀察環境即時變化。
:::
### 實作三:
手機透過藍牙,反向對 ESP32 遠距傳輸
>1. 依課本 p.93,上傳程式
>1. App 連接 ESP32 藍牙裝置
:::warning
hint: BT.readString()
:::spoiler
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
}
void loop() {
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata=BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
}
delay(1);
}
```
:::
:::success
觀察:當在 App terminal 輸入後,電腦連續收到手機的訊息。
:::
### 實作四:
透過藍牙,手機和 ESP32 雙向溝通
>1. 依課本 p.94,上傳程式
>1. App 連接 ESP32 藍牙裝置
:::warning
hint: Serial.readString() 和 BT.readString()
:::spoiler
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
}
void loop() {
//檢查序列監控視窗是否有輸入資料
while (Serial.available()) {
//讀取序列資料
String Sdata = Serial.readString();
//傳輸給藍芽
BT.println(Sdata);
//顯示在序列視窗
Serial.println(Sdata);
}
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata = BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
}
delay(1);
}
```
:::
:::success
觀察:同時在 App terminal 和手機App看到雙向訊息。
:::
### 實作五:
透過手機藍牙向 ESP32 傳送控制指令
>1. 將綠、黃、紅 LED 分別連接至GPIO 15、2、4 位置
>1. 依課本 p.95,上傳程式
>1. App 連接 ESP32 藍牙裝置
>1. 在 App terminal 輸入數字
:::warning
:::spoiler
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
pinMode(15, OUTPUT); //綠色LED
pinMode(2, OUTPUT); //黃色LED
pinMode(4, OUTPUT); //紅色LED
}
void loop() {
//檢查序列內是否有資料
while (Serial.available()) {
//讀取序列資料
String Sdata = Serial.readString();
//傳輸給藍芽
BT.print(Sdata);
}
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata = BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
//檢查藍芽資料及相對的指令
//接收到"1":開綠燈
if (BTdata == "1") { digitalWrite(15, HIGH); }
//接收到"2":關綠燈
if (BTdata == "2") { digitalWrite(15, LOW); }
//接收到"3":開黃燈
if (BTdata == "3") { digitalWrite(2, HIGH); }
//接收到"4":關黃燈
if (BTdata == "4") { digitalWrite(2, LOW); }
//接收到"5":開紅燈
if (BTdata == "5") { digitalWrite(4, HIGH); }
//接收到"6":關紅燈
if (BTdata == "6") { digitalWrite(4, LOW); }
}
delay(1);
}
```
:::
:::success
觀察:輸入數字1~6後,查看燈號變化
現在可以手機藍牙遠距手動控制燈號了。
:::
### 實作六:
透過設定語音指令,以語音向 ESP32 傳送控制指令
>1. 依課本 p.100,輸入語音指令
>1. App 連接 ESP32 藍牙裝置
>1. 對手機 App 麥克風說話
:::success
觀察:當語音指令正確接受後,查看燈號變化
:::
## :bulb:程式語法思考題
如何同時使用手機 App 和 電腦序列視窗,雙向輸入控制指令?
:::warning
建議:是否該去理解C/C++的程式語言?
:::
### 思考題 參考程式
:::success
hint: 以 char 宣告 Serial 讀取字串, char 讀 'x', String 讀 "xx"
[參考 ~[C語言_01]字元陣列,字串傻傻分不清楚?by_Andy_Cheng~](https://medium.com/andy的趣味程式練功坊/c語言-01-字元陣列-字串傻傻分不清楚-45089f69f6be)
:::spoiler
### 思考題 參考程式(一)
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;
char Sdata;
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
pinMode(15, OUTPUT); //綠LED, pin#15
pinMode(2, OUTPUT); //黃LED, pin#2
pinMode(4, OUTPUT); //紅LED, pin#4
}
void loop() {
while (Serial.available()>0) {
//讀取序列資列
Sdata = Serial.read();
Serial.print(Sdata);
if (Sdata == '1') {digitalWrite(15,HIGH);}
if (Sdata == '2') {digitalWrite(15,LOW);}
if (Sdata == '3') {digitalWrite(2,HIGH);}
if (Sdata == '4') {digitalWrite(2,LOW);}
if (Sdata == '5') {digitalWrite(4,HIGH);}
if (Sdata == '6') {digitalWrite(4,LOW);}
//傳輸給藍牙
BT.print(Sdata);
}
delay(1);
//檢查藍牙內是否有資料
while (BT.available()) {
//讀取藍牙資料
String BTdata=BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
//檢查藍牙資料及相對的指示
if (BTdata == "1") {digitalWrite(15,HIGH);}
if (BTdata == "2") {digitalWrite(15,LOW);}
if (BTdata == "3") {digitalWrite(2,HIGH);}
if (BTdata == "4") {digitalWrite(2,LOW);}
if (BTdata == "5") {digitalWrite(4,HIGH);}
if (BTdata == "6") {digitalWrite(4,LOW);}
}
delay(1);
}
```
:::
:::success
hint: 讀取序列字串 Serial.readStringUntil(),Terminal 輸出以 '\n' 結尾
:::spoiler
### 思考題 參考程式(二)
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
pinMode(15, OUTPUT); //綠LED, pin#15
pinMode(2, OUTPUT); //黃LED, pin#2
pinMode(4, OUTPUT); //紅LED, pin#4
}
void loop() {
while (Serial.available()) {
//讀取序列資列
String Sdata = Serial.readStringUntil('\n');
Serial.println(Sdata);
if (Sdata == "1") {digitalWrite(15,HIGH);}
if (Sdata == "2") {digitalWrite(15,LOW);}
if (Sdata == "3") {digitalWrite(2,HIGH);}
if (Sdata == "4") {digitalWrite(2,LOW);}
if (Sdata == "5") {digitalWrite(4,HIGH);}
if (Sdata == "6") {digitalWrite(4,LOW);}
//傳輸給藍牙
BT.print(Sdata);
}
delay(1);
//檢查藍牙內是否有資料
while (BT.available()) {
//讀取藍牙資料
String BTdata=BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
//檢查藍牙資料及相對的指示
if (BTdata == "1") {digitalWrite(15,HIGH);}
if (BTdata == "2") {digitalWrite(15,LOW);}
if (BTdata == "3") {digitalWrite(2,HIGH);}
if (BTdata == "4") {digitalWrite(2,LOW);}
if (BTdata == "5") {digitalWrite(4,HIGH);}
if (BTdata == "6") {digitalWrite(4,LOW);}
}
delay(1);
}
```
:::
:::success
hint: 以自建函式庫 function
:::spoiler
### 思考題 參考程式(三)
```javascript=
#include <BluetoothSerial.h>
BluetoothSerial BT;
void setup() {
Serial.begin(115200);
BT.begin("");//請改名
pinMode(15, OUTPUT); //綠LED, pin#15
pinMode(2, OUTPUT); //黃LED, pin#2
pinMode(4, OUTPUT); //紅LED, pin#4
}
void loop() {
while (Serial.available()) {
//讀取序列資列
String Sdata = Serial.readStringUntil('\n');
Serial.println(Sdata);
//檢查藍牙資料及相對的指示
judgeled(Sdata);
//傳輸給藍牙
BT.print(Sdata);
}
delay(1);
//檢查藍芽內是否有資料
while (BT.available()) {
//讀取藍芽資料
String BTdata=BT.readString();
//顯示在序列視窗
Serial.println(BTdata);
//檢查藍牙資料及相對的指示
judgeled(BTdata);
}
delay(1);
}
void judgeled(String input) {
if (input == "1") {digitalWrite(15,HIGH);}
if (input == "2") {digitalWrite(15,LOW);}
if (input == "3") {digitalWrite(2,HIGH);}
if (input == "4") {digitalWrite(2,LOW);}
if (input == "5") {digitalWrite(4,HIGH);}
if (input == "6") {digitalWrite(4,LOW);}
}
```
:::
## :wink:自主練習題
如何以語音啟動三種不同亮燈模式的 WS2812?
>閃綠圈
>閃黃圈
>閃紅圈
>
## 參考資料
>1)IOT物聯網應用第七章 – 尤濬哲(夜市小霸王) 編著
>2)[Infrared Remote & Receiver Module](https://www.jsumo.com/infrared-remote-receiver-module)
>3)[ESP32 Bluetooth Low Energy By Fernando Koyanagi in Circuits](https://www.instructables.com/ESP32-Bluetooth-Low-Energy/)
>4)[MANET Network in Internet of Things System WRITTEN BY Rasa Bruzgiene, Lina Narbutaite and Tomas Adomkus](https://www.intechopen.com/chapters/53178)
>5) [[C語言_01] 字元陣列,字串傻傻分不清楚?by Andy Cheng](https://medium.com/andy的趣味程式練功坊/c語言-01-字元陣列-字串傻傻分不清楚-45089f69f6be)