TOP PAGE

ESP32-S3でのMicroPythonで、遠隔制御用のTCPサーバーを構築する

ESP32の遠隔制御用のTCPサーバーは、このリンク先で紹介しています。
ここでは、ESP32-S3を使っている「ESP32-S3-DEV-KIT-N16R8-M」に、MicroPythonをインストールし、そこに遠隔制御用のTCPサーバーを構築する過程を紹介しています。
このサーバーは、このモジュールがWifiのアクセスポイントにして、PC側からファイル送信やファイル実行などを遠隔操作できる機能です。

その前にESP32とESP32-S3のおおまかな比較を以下に示します。
コアプロセッサピン数RAMBluetooth備考
ESP32-WROOM-32E 16MBXtensa 32-bit LX638ピンSRAM:520KBv4.2 BR/EDR, LE
ESP32-S3-WROOM-1-N16R8Xtensa 32-bit LX740ピンSRAM:520KB/PSRAM:8MBv5.0 LEAIアクセラレータ、DSP命令セット

ESP32-S3-WROOM-1-N16R8には、8MBのPseudo Static RAMがあり、SPIを介して使われるらしいが、MicroPythonの変数で利用できるようです。

右写真がESP32-S3-WROOM-1-N16R8のイメージで、上のタクトスイッチがRESET、下のスイッチがBOOTです。

以下でこのモジュールへ電源さえ供給すれば、Wifiを介してPCから遠隔操作するサーバーを構築する方法を紹介します。
(ESP32のMicroPythonのパワーON時の起動ファイルが boot.py に決まっており、 サーバの起動はboot.pyからsetap.pyとserver.pyを呼びだすことで実現します。)

遠隔操作の目標はファイルの送信と実行ですが、他にこのリンク先で 紹介したファイル操作(ファイルリスト取得、テキストファイル内容の表示、ファイルダウンロード、Pythonファイルのimport起動)も可能にしました。
ここで紹介しているサーバー(server.py)に接続して制御するクライアントプログラム(client_esp32.py)の使い方の概要を紹介します。

Wifiアクセスポイントの'ESP32S3-AP'に接続したPC側のコマンドプロンプトでpython client_esp32.pyと実行させます。
IP (defualt:192.168.220.1)Address>のプロンプトに対して変更なければEnterを入力します。

接続できればConnect!と表示され、入力:M/F/'quit'?>のメニューが 表示されます。

このメニュー入力に対いて、quitを入力すると、サーバー(server.py)終了してクライアントを終了します。
(再度、client_esp32.pyを使うためには「ESP32-S3-DEV-KIT-N16R8-M」を再起動しなければなりません)

このメニュー入力に対いて、Fを入力すると、PC側の送信対象を見極めるファイル名などリストが表示され、
送信したいファイル名入力>のプロンプトが出ます。正しくファイル名を入力すればそれがサーバーにファイル転送されます。
fを入力すると、遅いけど大きなファイル転送が可能な処理が行えます。)

このメニュー入力に対いて、Mを入力すると、"ls -l/cat /get /del /import >"のサブメニューが出現します。
このサブメニューに対する各コマンド入力に対する概要を以下に示します。
(ls -l以外のコマンドには、直後に半角スペース一つで区切った文字列の■■■で情報を追加します。)
入力文字列概要
ls -lサーバー側のファイルリストを得るコマンド。(入力データの前後に余計なスペースを入力しない)
cat ■■■サーバー側の■■■の名前のテキストファイル内容を得るコマンド。
get ■■■サーバー側の■■■の名前のファイル内容をクライアントにダウンロードするコマンド。
del ■■■サーバー側の■■■の名前のファイルを削除するコマンド。
import ■■■サーバー側の■■■の名前のモジュール(.pyを含まない)をimport実行させるコマンド。

簡単な実行例を、メモリ情報確認のリンク先や、操作例のリンク先で紹介しています。

ESP32-SにMycroPythonをインストールするまで

ESP32とPCをUSBで接続後、PCのデバイスマネージャーで、接続したポート(COMとLPT)を確認しておく必要があります。
私の場合、デバイスマネージャーのの画面からCOM3が使われていると分かります。
(このCOM番号が得られない場合、ドライバーのインストールが必要です)
下記はESP3のUSB接続がCOM3の場合の例です。
「Tera Term」では、次のように「Serial Port...」を選択してUSB接続で分かったCOM番号など、次のように設定してOKします。


そして、Fileメニューから「New Conection...」を選択してCOM3(上記のデバイスマネージャー表示時はCOM4でもOK)を選んでOKします。
このように接続して、ESP32-S3-WROOM-1-N16R8のRESETタクトスイッチを押すと、「Tera Term」に次のような表示が現れます。
(表示しない場合は、「Tera Term」内でEnterを入力すると表示さる場合があります)
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4037b36a
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3818,len:0x109c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xb50
load:0x403cc700,len:0x2fd0
entry 0x403c98ac
/********** RAM Test**********/
ESP32-S3 Flash and PSRAM size detection
Flash size: 16777216 bytes
Free PSRAM size: 8385412 bytes
Flash and PSRAM is OK!
/******* RAM Test Over********/
/**********WiFi Test**********/
13 networks found
Nr | SSID                             | RSSI | CH | Encryption
 1 | 000740E60153                     |  -25 |  7 | WPA+WPA2
 2 | HUMAX-EC0AA                      |  -67 | 11 | WPA+WPA2
 3 | HUMAX-4AC08                      |  -72 |  1 | WPA+WPA2

/*******WiFi Test Over********/

MicroPythonのインストールには、esptoolを使います。
PC側のPythonが動く環境で、esptoolのインストールは、次のように行います。
pip install esptool
Jul. 2025に行った時、「esptool 3.3.3」がインストールされました。
(これにより私の環境では、R:\Python36\Scripts\esptool.exe が配置されました。
以下では、この絶対パスを使って操作した例ですので、実際にインストールした環境に合わせてください。)

予め、https://micropython.org/download/ESP32_GENERIC_S3/から インストール用のバイナリーファイルをダウンロードしておきます。
以下は、Jul. 2025時点の最新ファームウェア(Octal-SPIRAM対応)の 「ESP32_GENERIC_S3-SPIRAM_OCT-20250415-v1.25.0.bin」をダウンロードしてそれを使った例です。

まず、次のようなコマンド操作で、「ESP32-S3-WROOM-1-N16R8」を初期化します。
(「Tera Term」の接続は終了して操作します。)
R:\work> R:\Python36\Scripts\esptool.exe --port COM3 erase_flash
esptool.py v3.3.3
Serial port COM3
Connecting....
Detecting chip type... ESP32-S3
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: 94:a9:90:03:67:9c
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 8.4s
Hard resetting via RTS pin...


次に、次のようなコマンド操作で、ダウンロードしたファイルで「ESP32-S3-WROOM-1-N16R8」にMicroPythonのインストールします。
R:\work> R:\Python36\Scripts\esptool.exe --port COM3 write_flash 0 ESP32_GENERIC_S3-SPIRAM_OCT-20250415-v1.25.0.bin
esptool.py v3.3.3
Serial port COM3
Connecting....
Detecting chip type... ESP32-S3
Chip is ESP32-S3 (revision v0.2)
Features: WiFi, BLE
Crystal is 40MHz
MAC: 94:a9:90:03:67:9c
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00199fff...
Compressed 1676624 bytes to 1098448...
Wrote 1676624 bytes (1098448 compressed) at 0x00000000 in 96.8 seconds (effective 138.6 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
以上で、「ESP32-S3-WROOM-1-N16R8」にMicroPythonをインストールする処理が終了です。

ESP32-S3をアクセスポイントにして、遠隔制御用のTCPサーバーが自動的に起動するまでの設定

前述のMicroPythonのインストールの後、COMのシリアル接続した「Tera Term」と、Pythonが動くPCのコマンドラインで作業しします。
「Tera Term」で接続後、ESP32-S3-WROOM-1-N16R8のRESETボタンを押すと、 「Tera Term」の内容は、次の表示とともにMicroPythonの会話モードの画面になります。
MicroPython v1.25.0 on 2025-04-15; Generic ESP32S3 module with Octal-SPIRAM with ESP32S3
Type "help()" for more information.
>>>
>>>

この画面に、MicroPythonのコードを貼り付けて実行できます。
次のコードを貼り付けることで、のsetap.pyファイルが生成されます。
これは、アクセスポイントとなり、ESP32-S3のIPアドレスを192.168.220.1にしてDHCPサーバーが起動するためコードです。
fw = open('setap.py', 'w')
fw.write("import time # setap.py\n")
fw.write("time.sleep(5)\n")
fw.write("import network\n")
fw.write("ap = network.WLAN(network.AP_IF) # create access-point interface\n")
fw.write("ap.config(essid='ESP32S3-AP') # set the ESSID of the access point\n")

fw.write("ap.config(max_clients=10) # set how many clients can connect to the network\n")
fw.write("ap.ifconfig(('192.168.220.1', '255.255.255.0', '192.168.220.1', '8.8.8.8'))\n")
fw.write("# set (ip address, subnet mast, default gateway, dns ip address)\n")
fw.write("ap.active(True)         # activate the interface\n")
fw.close()
上記の貼り付け実行で、正しく'setap.py'のファイルが出来上っているかは、次のコードの実行で確認出来ます。
with open('setap.py', 'r') as fr:
    for s in fr.readlines():print(s, end="")
'setap.py'の実行は、次のコードを貼り付けることで行います。
import setap
上記の実行後、WindowsなどのWifiを確認して、'ESP32S3-AP'のアクセスポイントが見えて接続できればOKです。

次は、TCPでファイルを受信するサーバーをfilerec.pyの名前で作るコードです。
次のコードをコピーして「Tera Term」画面に貼り付けで実行させます。
fw = open('filerec.py', 'w')
fw.write("import socket\n")
fw.write("portnumber=59154\n")
fw.write("ip = '192.168.220.1'\n")
fw.write("server_addr =(ip, portnumber)\n")
fw.write("serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n")
fw.write("serversock.bind(server_addr)  # IP and port number\n")
fw.write("serversock.listen(1)\n")
fw.write("print(f'{serversock}:\\n start server')\n")
fw.write("sock, address = serversock.accept()\n")
fw.write("print('client address:',address)\n")
fw.write("serversock.close()\n")
fw.write("\n")

fw.write("buf=b'' # For receiving file names and sizes\n")
fw.write("sock.recv(1)        # receieve 'F'\n")
fw.write("while True:\n");
fw.write("    bin = sock.recv(1)        # receieve 1byte\n")
fw.write("    if len(bin) != 1: break   # close or error ?\n")
fw.write("    buf += bin\n")
fw.write("    if buf[-2:] == b'\\r\\n': # end line ?\n")
fw.write("        s = buf[0:-2].decode('utf-8')# binarry to str\n")
fw.write("        print(s)\n")
fw.write("        a=s.split(' ')\n")
fw.write("        filename, filesize = a[0], int(a[1])\n")
fw.write("        print('filename:',  filename, ',  filesize:', filesize) \n")

fw.write("        with open( filename, 'wb') as f:\n")
fw.write("            for n in range(filesize):\n")
fw.write("                bin = sock.recv(1)\n")
fw.write("                f.write(bin)\n")
fw.write("        print('received:', filesize, 'byte.')\n")
fw.write("        sock.close()\n")
fw.close()
上記の貼り付け実行で、正しく'filerec.py'のファイルが出来上っているかは、次のコードの貼り付けでソースコードを確認出来ます。
with open('filerec.py', 'r') as fr:
    for s in fr.readlines():print(s, end="")
上記のファイル受信するサーバーは、接続したクライアントから、次のフォーマットの受信で、そのファイルをESP32-3S側に保存するように作られています。

F「ファイル名」 「ファイルサイス」改行「ファイルサイスに対応するバイナリのバイト列」
先頭にFの文字があり、続けて「受け取るファイル名」、直後に半角スペースが1つ、その後に「ファイルサイス」の10進文字列と改行が在ります。
ここまでがテキスト情報で、この直後に「ファイルサイス」に対応する受信するバイナリのバイト列が並ぶイメージです。


次は上記のファイル受信サーバーに対して、ファイルを送信するクライアントをPC側で作ります
次の内容で、filesnd.pyの名前のファイルを作ります。
import socket # filesnd.py
import os
import time
def sendFile(sock: socket, filename:str):
    filesize = os.path.getsize(filename)
    s = "F{} {}".format(filename, filesize)
    bin=(s+"\r\n").encode("utf-8") # to binary
    print(bin, end="  ")
    sock.sendall(bin) # send filename filesize
    with open(filename, "rb") as f:
        bin = f.read(filesize)
    # print("send data:" , bin )
    sock.sendall(bin) # send all file
    print("send byte:" , len(bin) )

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
portnumber=59154
ip="192.168.220.1"
sock.connect((ip, portnumber))
print(f"{sock}:接続しました。")
filename = input("送信したい文字ファイル名入力>");
sendFile(sock, filename) #ファイルを送信
time.sleep(1)
sock.close()
以上までの操作で、ESP32-S3にファイルを送信する準備ができました。

これを使って、別途にこのリンク先のserver.pyを作って置き、それをESP32-S3に送信します。
(この送信するファイル(server.py)は、filesnd.pyのファイル位置と同じ位置に置いて起きます。)

このserver.pyを、PCからESP32-S3へ送信します。
それには、前述で行ったように「Tera Term」画面でESP32側のfilerec.pyモジュールをimportで実行させます。次の操作です。
(失敗した場合は、ESP32-S3-DEV-KIT-N16R8-M」を再起動してから行うとよいでしょう。)
まず、「Tera Term」画面でESP32側のfilerec.pyモジュールをimportで実行させます。
>>> import setap
>>> import filerec
<socket>:
 start server

この実行結果(start serverの表示)で、サーバーが起動しているのが分かります。
次にPC側のWifi接続画面で、'ESP32S3-AP'のアクセスポイントのアクセスポイントに接続します。

次は、PC側でファイル送信のクライアント(filesnd.py)を起動です。
そして、PC側のipconfigコマンドなどで192.168.220.0のネットワークに接続できたことを確認します。
以下は、PC側でクライアント(filesnd.py)を起動して、server.pyのファイルをESP32に送信している例です。
D:\ESP32-S3-DEV-KIT-N16R8-M>python filesnd.py
<socket.socket fd=396, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.220.2', 56245), raddr=('192.168.220.1', 59154)>:接続しました。
送信したい文字ファイル名入力>server.py
b'Fserver.py 8673\r\n'  send byte: 8673

D:\ESP32-S3-DEV-KIT-N16R8-M>
上記は、PC側の8673バイトのserver.pyのファイルを送信した場合のコンソール画面です。
そして、以下はESP32側の「Tera Term」画面が次のように変化します。
>>> import setap
>>> import filerec
<socket>:
 start server
client address ('192.168.220.2', 59693)
server.py 8673
filename: server.py ,  filesize: 8673
received: 8673 byte.
>>>
おおよそこのような結果が得られれば、server.pyがESP32-S3-DEV-KIT-N16R8-Mに送信されたことになります。

ここで、ESP32-S3-DEV-KIT-N16R8-MのRESETボタンで再起動させ、server.pyの動作を検証します。
まず、server.pyのサーバーに対応したPC側クライアントソフトを用意する必要があります。
PC側クライアントソフトのclient_esp32.pyを、このリンク先の内容で用意します。

そして検証として、下記のdf.pyをESP32-S3-DEV-KIT-N16R8-Mに送信してそこで実行させます。

このdf.pyは、ESP32-S3の使用状況や空状態と使えるメモリ容量を表示させるコードです。
import server
print = server.send # printをクライアントへ出力する機能に置き換える
import os
import gc

stat = os.statvfs('/')
block_size = stat[0]  # 1ブロックのサイズ(バイト単位)
total_blocks = stat[2]  # f_blocks(総ブロック数)
free_blocks = stat[3] # 空きブロック数
print(f"block_size: {block_size} bytes, free_blocks: {free_blocks}")
free_space=block_size * free_blocks  # 空き容量(バイト単位)
print(f"Free space: {free_space} bytes")
total_size = block_size * total_blocks  # 総容量(バイト)
print(f"Total Storage: {total_size} bytes\n")

print(f"Allocatable memory size:{gc.mem_free()}") # 今どのくらいヒープが空いているかのサイズ(byte)確認

上記の内容でdf.pyをclient_esp32.pyと同じ位置に作って、次のように検証します。
ESP32-S3-DEV-KIT-N16R8-Mを再起動して、「Tera Term」画面でESP32-S3側のsetapとserverモジュールをimportで実行させます。
>>> import setap
>>> import server
そして、 PC側のWifi接続画面で'ESP32S3-AP'のアクセスポイントのアクセスポイントに接続します。

そして、PC側のclient_esp32.pyがある位置をカレントディレクトリにプロンプトで次のように動作確認します。
以下は、この実行例です。 上記の df.py をアップロードして、それを実行しています。 黄色文字部がキー入力の部分です。
D:\ESP32-S3-DEV-KIT-N16R8-M>python client_esp32.py
IP (defualt:192.168.220.1)Address>

Connect!
入力:M/F/'quit'?>F
['boot.py', 'client_esp32.py', 'df.py', 'ESP32_GENERIC_S3-SPIRAM_OCT-20250415-v1.25.0.bin', 'filesnd.py', 'rec', 'server.py']
送信したいファイル名入力>df.py
送信byte: 760
Starting to receive df.py:size=760 Please wait.

df.py size:760, 760bytes receive end.
入力:M/F/'quit'?>M
ls -l/cat /get /del /import >import df
Send:import df
import_name:df
block_size: 4096 bytes, free_blocks: 1528
Free space: 6258688 bytes
Total Storage: 6291456 bytes

Allocatable memory size:8262160
入力:M/F/'quit'?>quit
receiveData ended.

D:\ESP32-S3-DEV-KIT-N16R8-M>
以上のように実行できて、ESP32-S3-WROOM-1-N16R8で使えるメモリが8262160と分かります。
上記では、quitで終了していますが、これでサーバー側(server.py)も終了して「Tera Term」のプロンプトが復帰します。
サーバー側のserver.pyが動作している間は、「Tera Term」の操作はできません。
quitで終了した後は、連続して client_esp32.pyによる制御ができません。ESP32-S3-WROOM-1-N16R8をRESETして再接続する必要があります。

以上のような実行がえられれば、server.pyの動作を検証ができたことになります。

server.pyを起動時に実行するためのboot.pyの設定

そのために、boot.pyで起動モジュールimportします。そのboot.pyをPC側で、次の内容で作成します。
import setap
import server
上記で作成したboot.pyを転送する方法を示します。
一度、ESP32を再起動させます。
「Tera Term」画面でESP32側のserver.pyモジュールをimportで実行させます。次の操作です。
>>> import setap
>>> import server
以上でserver.pyを起動しました。
そしてPC側のWifi接続画面で、'ESP32S3-AP'のアクセスポイントに接続します。
これでPC側からclient_esp32.pyで次のようにファイルを送ります。
黄色文字部がキー入力の部分です。
D:\ESP32-S3-DEV-KIT-N16R8-M>python client_esp32.py
IP (defualt:192.168.220.1)Address>

Connect!
入力:M/F/'quit'?>F
['boot.py', 'client_esp32.py', 'df.py', 'ESP32_GENERIC_S3-SPIRAM_OCT-20250415-v1.25.0.bin', 'filesnd.py', 'rec', 'server.py']
送信したいファイル名入力>boot.py
Server:'boot.py' 40bytes received.
入力:M/F/'quit'?>quit
Send:end_listen_loop
receiveData ended.

D:\ESP32-S3-DEV-KIT-N16R8-M>
正しい内容であれば、ESP32の基板のUSBケーブルをPCから抜いて、代わりにUSBの電源アダプタに繋いで起動します。
これで、Wifiアクセスポイントとしてsetap.pyが起動し、192.168.220.1の遠隔制御用サーバーのserver.pyが起動します。
そしてPC側から、python client_esp32.pyでファイル送信や実行ができます。 (終了させるまで「Tera Term」の操作ができません
以上でサーバー構築まで解説は、おしまいです。

この時点で、client_esp32.pyによる操作ができない状態で、「Tera Term」も操作できない場合、 ESP32-S3-DEV-KIT-N16R8-Mを初期化して、MicroPythonのインストールからやり直す必要があります。

なお、booy.pyの最後に起動さたいモジュールを追加すると、python client_esp32.pyの実行をquitで追加したモジュールを起動することができます。
ですが、booy.pyにserverの代わりに、起動さたいモジュールを記述すると、それ専用のモジュールになりますが、それが正しく終了できるようになっていないと、 「Tera Term」でも操作ができなく、ESP32-S3-DEV-KIT-N16R8-Mを初期化からの再設定を必要とするでしょう。


ESP32-S3-WROOM-1-N16R8用最終版の遠隔制御用のTCPサーバーのソース(server.py)

import os   # server.py ESP32用 (UME用を除いたコード)
import sys
import socket
import _thread
import time
#import esp
#esp.osdebug(None) # ベンダ O/S デバッグメッセージをオフにする

path_datas = "./"
flag_listen_loop=True
sock2=None # TCPクライアントと通信するソケット

def tcp_send_message(sock,msg): # sockのクライアント側にメッセージ送信
    bin=('M'+msg+"\r\n").encode("utf-8")
    if sock : sock.sendall(bin)

def send(msg):# sock2のクライアント側にメッセージ送信
    msg=f"{msg}" # 文字列へ変換
    if sock2 is None: return
    a=msg.split("\n")
    for s in a:
        tcp_send_message(sock2,s)

def ls_filelist(sock,path): # ファイルリストの文字列をクライアントに送信
    tcp_send_message(sock,"ls_filelist:" + path)
    if path == "": path="."
    try:
        for f_name in os.listdir(path) :
            file_info = os.stat(f_name)
            file_size = file_info[6]
            d_inf = 'dir' if (file_info[0] & 0x4000 ) else '   ' # ディレクトリ判定
            msg = f"{d_inf} {file_size:7}  {f_name}"
            tcp_send_message(sock, msg)
    except Exception as e:
        tcp_send_message(sock,"ls_filelist Error:" + str(e))

def cat_filepath(sock, filepath): # filepathのテキスト内容をクライアントに送信
    tcp_send_message(sock, "cat_filepath:" + filepath)
    try:
        with open(filepath, 'r', encoding='utf-8') as fr:
            ss = fr.readlines()
        for s in ss: 
            if s[-1] == '\n' : s=s[:-1] # 改行を除く
            tcp_send_message(sock, s)
    except Exception as e:
        tcp_send_message(sock,"cat_filepath Error"+ str(e))    

def del_filepath(sock, filepath): # filepathのファイルを削除
    tcp_send_message(sock, "del_filepath:" + filepath)
    try:
        os.remove(filepath)
    except Exception as e:
        tcp_send_message(sock,"del_filepath Error:"+ str(e))    

def import_name(sock, name):# nameのモジュールのPythonソースを実行
    tcp_send_message(sock, "import_name:" + name)
    try:
        mod=__import__(name) # 動的なインポートで実行
        del sys.modules[name] # 再度インポートできるように開放
    except Exception as e:
        tcp_send_message(sock,"import_name Error:"+ str(e))

def send_file(sock, filepath):# filepathのファイルをクライアントに送信
    try:
        idx_last_sep = filepath.rfind('\\')
        filename = filepath if idx_last_sep == -1 else filepath[idx_last_sep+1:]
        file_info = os.stat(filepath)
        filesize = file_info[6]
        s = "f{} {}".format(filename, filesize)
        bin=(s+"\r\n").encode("utf-8")
        sock.sendall(bin) #send filename filesize
        if filesize > 0:
            with open(filepath, "rb") as f:
                bin = f.read(filesize)
            sock.sendall(bin) # send binary file
        #
        tcp_send_message(sock,"server:send_file:"+ filepath)  
    except Exception as e:
        tcp_send_message(sock,"server:send_file Error:"+ str(e))    

def recieve_file(sock):# TCPでファイルを受信(1byte受信の繰り返し)
    buf=b""
    while True:
        bin = sock.recv(1)
        if bin == b'': break
        buf += bin
        if buf[-2:] == b"\r\n":
            s = buf[0:-2].decode('utf-8')
            a=s.split(' ')
            filename, filesize = a[0], int(a[1])
            f=open( path_datas + filename, "wb") # 受信ファイルの保存
            n=0
            tcp_send_message(sock,f"Starting to receive {filename}:size={filesize} Please wait.")
            while n < filesize:
                bin = sock.recv(1)
                if bin == b'': break
                f.write(bin)
                n += 1
                if n % 10000 == 0: tcp_send_message(sock,f"\n{n}bytes were received.")
            #
            f.close()
            tcp_send_message(sock,f"\n{filename} size:{filesize}, {n}bytes receive end.")
            if filename.endswith(".umh"):
                send_cmdfile(sock,filename) # ファイルのコマンド内容をUMEHOSHI ITAへ送信
            break
        #
    #print(filename + ":size=" + str(filesize)) # debug ---------------

def recieve_file_Max(sock):# TCPでファイルを受信(バッファを最大して受信)
    buf=b""
    while True:
        bin = sock.recv(1)
        if len(bin) != 1: break
        buf += bin
        if buf[-2:] == b"\r\n":
            s = buf[0:-2].decode('utf-8')
            a=s.split(' ')
            filename, filesize = a[0], int(a[1])
            bin=b""
            while len(bin) < filesize:
                bin += sock.recv(filesize-len(bin))
            with open( path_datas + filename, "wb") as f: # 受信ファイルの保存
                f.write(bin)
            tcp_send_message(sock,f"Server:'{filename}' {len(bin)}bytes received.")
            if filename.endswith(".umh"):
                send_cmdfile(sock,filename) # ファイルのコマンド内容をUMEHOSHI ITAへ送信
            break
        #
    #print(filename + ":size=" + str(filesize)) # debug ---------------

def recieve_message(sock): # 受信メッセージに対する処理
    global flag_listen_loop
    buf=b""
    while True:
        bin = sock.recv(1)
        if len(bin) != 1:
            flag_listen_loop = False
            return False
        #           
        buf += bin
        if buf[-2:] == b"\r\n":
            s = buf[0:-2].decode('utf-8').strip()
            if s == "end_listen_loop": # 受信文字列がこれと一致するなら終了
                flag_listen_loop = False
                return False
            #
            if s.startswith("ls -l"): # ファイルリスト要求に対する送信処理
                ls_filelist(sock, s[5:].strip() )
                return True
            #
            if s.startswith("cat "):# ファイル内容表示要求に対する送信処理
                cat_filepath(sock, s[4:] )
                return True
            #
            if s.startswith("del "):# ファイル削除要求に対する処理
                del_filepath(sock, s[4:] )
                return True
            #
            if s.startswith("import "):# Pythonファイルの実行要求に対する処理
                import_name(sock, s[7:] )
                return True
            #
            if s.startswith("get "): # ファイル要求に対するファイル送信
                send_file(sock, s[4:] )
                return True
            #
            if s.startswith("exc "): # .umhファイルの内容で、[UMEHOSHI ITA]のUART1に出力する。
                send_cmdfile(sock, s[4:] )
                return True
            #
            if len(s)>1 and s[0] in "SRG": 
                print( s ) # 受信文字列を、UME専用Hexコマンドと判断して、UMEHOSHI ITAへ送信
            else:
                tcp_send_message(sock,s) # 受信文字列を、TCPクライアントへECHO送信
            #
            return True

def receiveData(sock): # 受信処理ループ
    # tcp_send_message(sock,"start sever receiveData" )
    while True:
        bin = sock.recv(1)#1byte recieve
        if len(bin) != 1: break
        if bin == b"f" : recieve_file(sock)
        elif bin == b"F" : recieve_file_Max(sock)
        elif bin == b"M" : recieve_message(sock)
        else:
            tcp_send_message(sock,"server receive error:" + str(bin) )
    #

# UME(https://manabu.quu.cc/up/ume/ume_esp32_python.html)用で除いた箇所の部分がここに存在していた。

# ------------- Main -------------------
portnumber=59154
ip = "192.168.220.1"
#ip = "192.168.222.1"
#ip = "192.168.0.110"
server_addr =(ip, portnumber)
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind(server_addr)
#time.sleep(3.1) # 3.1秒待機 ([UMEHOSHI ITA]の初期でUME用で不要)
#thread_id = _thread.start_new_thread(input_loop, ()) #UME用で入力用スレッドのUME用で不要
serversock.listen(1) # TCPサーバ受け入れ待機
while flag_listen_loop:
    #
    sock2, address = serversock.accept() # クライアントの接続許可
    serversock.close() # 接続は一回だけで、再度使う場合はRESETボタンを押すか、電源供給をし直す。
    tcp_send_message(sock2, "\nConnect!") # TCPクライアントへのメッセージ
    try: 
        receiveData( sock2 ) # 受信応答処理のループ
    except: pass
    # print(cmd) # ― ― ― ― の音で終了処理で、UME用により不要
    sock2.close()
print("server.py ended")
上記のコードをserver.pyの名前で作ります。
このコードは、UMEHOSHI ITA基板に取り付けたESP32用のserver.pyから余計なコードを除いた処理です。
これは、ファイル受信以外に、 ファイルリスト取得、テキストファイル内容の表示、ファイルダウンロード、Pythonファイルのimport起動などを可能にするサーバーのコードです。
これに接続するクライアントソフトは、client_esp32.pyです。
(注意:セットの後、後述するクラシアンと接続できるのは一回だけです。)

上記で実行したESP32の遠隔制御用サーバーを制御するクライアント(client_esp32.py)の内容

ESP32の基板をUSBの電源アダプタに繋いで起動します。
前述の操作が終わっていれば、この電源を供給で、ESP32がWifiアクセスポイントになっています。
そしてESP32は、192.168.220.1:59154の遠隔制御用サーバー(server.py)が起動します。
この上記サーバー(server.py)は、MicroPythonで動作しており、ESP32-S3への任意ファイルアップロード、ダウンロード、 ルートディレクトリのリスト情報出力、任意テキストファイル内容の情報出力、ファイルの削除、pythonモジュールの実行、サーバーの実行終了 をクライアントから要求できるように作っています。
以下にこのサーバーを制御するコンソール用のクライアントソフト(client_esp32.py)を紹介します。
このクライアントは、UMEHOSHI ITA基板に取り付けたESP32のサーバーに対するクライアントソフトから、余計なコードを除いて作成したコードです。
import os 		# client_esp32.py
import socket
import sys
import time
import threading

path_datas="./"

# ----- 受信関連 ---------------------------------
def recieve_file(sock):
    buf=b""
    while True:
        bin = sock.recv(1)
        if len(bin) != 1: break
        buf += bin
        if buf[-2:] == b"\r\n":
            s = buf[0:-2].decode('utf-8')
            a=s.split(' ')
            filename, filesize = a[0], int(a[1])
            bin=b""
            while len(bin) < filesize:
                bin += sock.recv(filesize-len(bin))
            with open( path_datas + filename, "wb") as f:
                f.write(bin)
            #tcp_send_message(sock,filename + ":size=" + str(len(bin)))
            break
    print(filename + ":size=" + str(filesize)) # debug ---------------

def recieve_message(sock): # TCP文字列メッセージ受信
    buf=b""
    while True:
        bin = sock.recv(1)#1byte受信
        if len(bin) != 1: break
        buf += bin
        if buf[-2:] == b"\r\n":# 1行の文字列受信終了?
            s = buf[0:-2].decode('utf-8')#バイナリから
            print(s)
            break

def receiveData(sock): # 全てのTCP受信のスレッド用関数
    #print( "start receiveData" )
    while True:
        try:
            bin = sock.recv(1)#1byte受信
        except Exception as e: break
        if len(bin) != 1: break
        if bin == b"f" : recieve_file(sock)
        elif bin == b"M" : recieve_message(sock)
        else: print(bin , end="")
    #
    print( "receiveData ended." )

# ----- 送信関連 ---------------------------------
def send_file(sock, filepath):
    try:
        filesize = os.path.getsize(filepath)
        filename = os.path.basename(filepath)
        s = "f{} {}".format(filename, filesize)
        bin=(s+"\r\n").encode("utf-8")#binaryへ変換
        # print(bin, end="  ")
        sock.sendall(bin) #filename filesize 送信
        with open(filepath, "rb") as f:
            bin = f.read(filesize)
        # print("送信data:" , bin )
        sock.sendall(bin) # ファイル内容一括送信
        print("送信byte:" , len(bin) )
    except Exception as e:
        print( "send_file error:" + str(e))

def send_file_Max(sock, filepath):
    try:
        filesize = os.path.getsize(filepath)
        filename = os.path.basename(filepath)
        s = "F{} {}".format(filename, filesize)
        bin=(s+"\r\n").encode("utf-8")#binaryへ変換
        # print(bin, end="  ")
        sock.sendall(bin) #filename filesize 送信
        with open(filepath, "rb") as f:
            bin = f.read(filesize)
        # print("送信data:" , bin )
        sock.sendall(bin) # ファイル内容一括送信
        #print("送信byte:" , len(bin) )
    except Exception as e:
        print( "send_file_Max error:" + str(e))

def send_message(sock,msg):
    bin=('M'+msg+"\r\n").encode("utf-8")#binaryへ変換
    sock.sendall(bin)#一括送信
    print(f"Send:{msg}")

# ----- メイン ---------------------------------
portnumber=59154
ip="192.168.220.1"
#ip="192.168.0.110"
s = input(f"IP (defualt:{ip})Address>")
if s != "": ip = s
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, portnumber))
#print("接続成功")
t_id = threading.Thread(target=receiveData, args=(sock,) )
t_id.start()
time.sleep(1.0)
loopFlag = True
cmd=""
while loopFlag:
    #s = input("入力:M/F/'quit'/w/a/s/d/b/?>")
    s = input("入力:M/F/'quit'?>")
    if s != "": cmd = s
    if cmd == 'M':
        # msg = input("UME HEX Command /exc /ls -l/cat /get /del /import >")
        msg = input("ls -l/cat /get /del /import >")
        send_message(sock,msg)
        cmd=' '
    elif cmd == 'f' or cmd == 'F':
        s='F'
        print(os.listdir(path_datas))
        filename = input("送信したいファイル名入力>")
        if not os.path.isfile(path_datas + "/" + filename):
            print( filename, "no exist")
            continue
        if cmd == 'f' : send_file(sock, path_datas + "/" + filename)
        if cmd == 'F' : send_file_Max(sock, path_datas + "/" + filename)
        cmd=' '
    elif cmd == 'quit':
        send_message(sock,'end_listen_loop') # サーバーも終了させる場合、実行させる
        loopFlag=False
    else:
        pass # 追加コマンド処理
    #
    time.sleep(1.0)

sock.close()
sys.exit(0)

上記コード実行例(使い方を示しています。)

ここでは、"Hello World"をクライアントのPCコンコール画面に表示するtest.pyをESP32にアップロードして、それを実行する例を示します。
この時に使うtest.pyは、PC側で次のように作ります。
import server

server.send("Hello World");
この状態で、ESP32の基板をUSBの電源アダプタに繋いで起動します。
そしてPC側のWifi接続画面で、'ESP32D-AP'のアクセスポイントに接続します。
そして、PC側のコマンドラインで、client.pyを実行して次のように操作します。
以下の操作は、'test.py'をESP32へアップロードし、ESP32側のファイルリストを表示し、アップロードした'test.py'内容を表示してから その'test.py'を実行し、次に'test.py'を削除してから再びファイルリストを表示し、最後にESP32のサーバーを終了しています。
D:\ESP32-S3-DEV-KIT-N16R8-M>client_esp32.py
IP (defualt:192.168.220.1)Address>		Enterのキー入力で、デフォルトのサーバに接続を要求

Connect!	サーバに接続したことを知らせる表示
入力:M/F/'quit'?>F		ESP32へアップロード指示のキー入力
['boot.py', 'client.py', 'filesnd.py', 'info', 'server.py', 'servertest', 'test.py']	クライアント側のディレクトリ表示
送信したいファイル名入力>test.py		ESP32へtest.pyをアップロードするのキー入力
Server:'test.py' 46bytes received.
入力:M/F/'quit'?>M		他の操作のメニュー表示を指示するキー入力
ls -l/cat /get /del /import >ls -l	ESP32側のファイルリスト表示を指示するキー入力
Send:ls -l
ls_filelist:
         27  boot.py
        962  filerec.py
        803  filesnd.py
       8673  server.py
        448  setap.py
        937  tcpfrec.py
         46  test.py
入力:M/F/'quit'?>M		他の操作のメニュー表示を指示するキー入力
ls -l/cat /get /del /import >cat test.py	他ESP32側のフtest.pyを表示を指示するキー入力
Send:cat test.py
cat_filepath:test.py
import server

server.send("Hello World");
入力:M/F/'quit'?>M		他の操作のメニュー表示を指示するキー入力
ls -l/cat /get /del /import >import test	testモジュールを実行させるキー入力
Send:import test
import_name:test
Hello World	testの実行で、得られた表示文字列
入力:M/F/'quit'?>M		他の操作のメニュー表示を指示するキー入力
ls -l/cat /get /del /import >get setap.py		setap.pyのファイルをPC側にダウンロード指示するキー入力
入力:M/F/'quit'?>M
ls -l/cat /get /del /import >del test.py		ESP32側のtest.pyを削除するキー入力
Send:del test.py
del_filepath:test.py
入力:M/F/'quit'?>M		
ls -l/cat /get /del /import >ls -l	ファイルリスト表示のキー入力で、削除できたことを確認
Send:ls -l
ls_filelist:
         27  boot.py
        962  filerec.py
        803  filesnd.py
       8673  server.py
        448  setap.py
        937  tcpfrec.py
入力:M/F/'quit'?>quit		終了を指示するキー入力
Send:end_listen_loop
receiveData ended.

D:\ESP32-S3-DEV-KIT-N16R8-M>
上記操作で、'test.py'をESP32へアップロードし、ESP32側のファイルリストを表示し、 アップロードした'test.py'のテキスト内容を表示してから その'test.py'を実行し、次に'test.py'を削除してから再びファイルリストを表示し、最後にESP32のサーバーを終了しています。

さて上記でESP32で実行させたtest.pyの内容は次の内容でした。
import server

server.send("Hello World");
このESP32の実行で、server.py内の.sendによってクライアント側に"Hello World"の文字列をTCP送信し、クライアント側での表示を実現しています。
つまり、ESP32で実するのpythonコードからクライアント画面に文字列を表示させる場合は、server.sendメソッドを使います。
しかし、、server.sendを使った表示コードはPC側での単体実行で、表示するコードとして使えません。
こそこで、れまでPC側で使っていたprint表示を変更せずに使う場合、次のようにソース先頭でprint関数をserver.sendに置き換えると良いでしょう。
import server
print = server.send # printをクライアントへ出力する機能に置き換える

print(Hello World");
上記のような赤の2行を追加すれば、print関数でクライアントへ表示させることができるようになります。
但し、この置き換えたprintの引数は一つだけで、複数の文字列出力には対応していないことに注意して使う必要があります。

複数の情報を1つのprintで表示させる場合は、フォーマット文字列で一つの引数になるようにまとめると良いでしょう。