ESP32のbluetooth用の画像専用FTPを作った件

##はじめに
qiita adavent calender 2020 12/24の記事です
始めての投稿なのでご容赦ください

ESP32のSPIFFSから画像データ(bitmap)を送りたかったので簡単な画像転送用のプログラムを作った話です

## 環境
送信側
・ESP32(Arduino)
受信側
・python
## コード
まず、ESP32側で必要なライブラリを読み込み、シリアルbluettohを始めます

```Arduino
#include <SPIFFS.h>
#include <FS.h>
#include <BITMAPDecoder.h>
#include "BluetoothSerial.h"

BITMAPDecoder bitmap = BITMAPDecoder();

BluetoothSerial SerialBT;

void setup(){
  SerialBT.begin("ESP32");
}
```

次にESP32側でループ処理に入り信号(f)を待たせます


```Arduino
void loop() {
  if(SerialBT.available() > 0){
    int i = SerialBT.read();
    if(i == 'f')
```

その間python側を起動させます
python側で、ライブラリをインポートし、新しくイメージオブジェクトを生成します

```python
import serial
from io import BytesIO
from PIL import Image
import time

img = Image.new('RGB',(32,32))
```

今回はサイズを決めています

次に、python側からシリアルbluetoothを開き、信号(f)を送信します

```python
ser = serial.Serial('/dev/cu.ESP32-ESP32SPP',115200,timeout=None)
time.sleep(2)
ser.write(b"f")
```

ここで少し間を入れておかないと、処理が追いつかなくなるようです
### 送信に関して
bitmapの左上から右上、戻って、1pixel下げて左から右を繰り返す形になります。



信号(f)を受信したESP32はSPFFSから画像ファイルを呼び出し、各pixelのRGBを読み込みます
ここで@DeepSpawnさんのライブラリを使用させていただきました

```Arduino
{
 SPIFFS.begin();
 File fp;
 fp = SPIFFS.open( "/sample.bmp","r" );
 bitmap.checkFile( fp );
 for( int Y=0 ; Y<bitmap.height() ; Y++ ){
   for( int X=0 ; X<bitmap.width() ; X++ ){
     PIXEL p = bitmap.readPixel( fp, X, Y );
```

ただ、RGBの配列のままだと一度に送ることができないので、16進数に変換して送信します

```Arduino
 int hex = p.r * 65536 + p.g * 256 + p.b;
 SerialBT.println(hex,HEX);
```

そして送信に成功することを確認する信号(r)を待ちます

```Arduino
 for(char i;i != 'r';){
            i = SerialBT.read();
           }
         }
```

その間、python側で各pixelのカラーコードを受信し、信号(r)を送信、各pixelに色を当てはめます

```Python
while True:
    color = ()
    for h in range(32):
        for w in range(32):
            date = ser.readline()
            date_str = date.decode('utf-8')
            date_fix = date_str.strip("\r\n")
            ten = int(date_fix,16)
            color = (int(ten/65536),int(ten%65536/256),int(ten%256))
            ser.write(b"r")
            img.putpixel((w+1,h+1),color)       
```

これらの処理を何度か繰り返したのち、ESP32側でファイルを閉じます

```Arduino
fp.close();
  }
```

Python 側ではImageオブジェ9tをファイルとして保存します

```Python
img.save('deta.jpg')
```
コード全体としては以下の通りです

```Arduino
#include <SPIFFS.h>
#include <FS.h>
#include <BITMAPDecoder.h>
#include "BluetoothSerial.h"

BITMAPDecoder bitmap = BITMAPDecoder();

BluetoothSerial SerialBT;

void setup(){
  SerialBT.begin("ESP32");
}
void loop() {
  if(SerialBT.available() > 0){
    int i = SerialBT.read();
    if(i == 'f'){
      SPIFFS.begin();
      File fp;
      fp = SPIFFS.open( "/sample.bmp","r" );
      bitmap.checkFile( fp );
      for( int Y=0 ; Y<bitmap.height() ; Y++ ){
        for( int X=0 ; X<bitmap.width() ; X++ ){
           PIXEL p = bitmap.readPixel( fp, X, Y );
           int hex = p.r * 65536 + p.g * 256 + p.b;
           SerialBT.println(hex,HEX);
           for(char i;i != 'r';){
            i = SerialBT.read();
           }
         }
    }
    fp.close();
  }
  }
  
}
```

```python
import serial
from io import BytesIO
from PIL import Image
import time

img = Image.new('RGB',(32,32))
ser = serial.Serial('/dev/cu.ESP32-ESP32SPP',115200,timeout=None)
time.sleep(2)
ser.write(b"f")

while True:
    color = ()
    for h in range(32):
        for w in range(32):
            date = ser.readline()
            date_str = date.decode('utf-8')
            date_fix = date_str.strip("\r\n")
            ten = int(date_fix,16)
            color = (int(ten/65536),int(ten%65536/256),int(ten%256))
            ser.write(b"r")
            img.putpixel((w,h),color)
            print(w)
            print(h) 
    else: 
        img.save('deta.jpg')
```
## 問題点
1.この方式では画像形式でしか対応していないこと(bitmap)
2.容量に制限がかかるSPIFFSからしかファイル呼び出せないこと
3.どうしても、速度が遅くなること

古典的な方法を使っているためどうしてもこのような問題点が出てきてしまいます

そこで

1.読み出し方法をpixel単位から、buffaを分割する方法を取る
2.SDカード等への対応
3.Bluetoothサーバーへの書き換えや、変数のデータを圧縮する方法が取れる

などの問題解決をGithub上でやろうと感じています。

## 最後に
bitmap読み込みライブラリを作ってくださった@DeepSpawnさま、藪からに質問をさせていただいた学校の知人の皆様、ありがとうございました！！