Завантаження зображення на FTP використовуючи CircuitPython на Cardputer
Скріпт для завантаження файлу, використовуючи з ESP32 Cardputer і CircuitPython. Може підійти для завантаження зображення з камери
Вже давно граюся з ESP32, котрий отртимує широкі можливості при використанні CircuitPython. CircuitPython це спеціальна версія мови программування Python опитимізована під велику кількість мікроконтролерів і дуже спрощує створення програм під мікроконтролери.
Я використовую Cardputer на базі контролеру ESP32 S3, який має клавіатуру та екран, проте достатньо мати будь яку Dev плату ESP32 з підтримкою USB.
Завантажити CiruitPython можно через M5Burner. В програмі треба зліва обрати потрібну плату – Cardputer і знайти Circuitpython. Далі потрібно підключити плату по USB, увімкнути та затиснути кнопку на боці корпусу GO
і натиснути Reset
, потім відтиснути GO
. Контролер перезавантажиться і M5Burner зможе ідентифікувати плату.
Тепер можно завантажити пакет CircuitPython та встановити. Після встановлення та перезавантаження контроллер іденифікується як USB-накопичувач. На цьому накопичувачі нас цікавлять два файли settings.toml
та code.py
. Для редагування файлів я рекомендую виокристовувати VSCode та розширення CircuitPython. Після встановлення розширення відкрийте накопичувач в якості проєкту VSCode і після цього встановіть необхідні бібліотеки, натиснувши Ctrl+P
та введіть > CircuitPython: Show Available Libraries
і виберіть наступні: adafruit_connection_manager
, adafruit_requests
.
В файлі settings.toml
додайте налаштування підключення до Wi-Fi:
1
2
3
4
5
6
7
CIRCUITPY_WIFI_SSID="<Назва Wi-Fi точки>"
CIRCUITPY_WIFI_PASSWORD="<Пароль>"
FTP_SERVER="<FTP сервер>"
FTP_PORT=21
FTP_USERNAME="<FTP юзернейм>"
FTP_PASSWORD="<FTP пароль>"
REMOTE_FILENAME="test.jpg"
В файлі code.py
додайте наступний код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import os
import adafruit_connection_manager
import wifi
import adafruit_requests
import socketpool
import errno
import time
WIFI_SSID = os.getenv("CIRCUITPY_WIFI_SSID")
WIFI_PASSWORD = os.getenv("CIRCUITPY_WIFI_PASSWORD")
FTP_SERVER = os.getenv("FTP_SERVER")
FTP_PORT = os.getenv("FTP_PORT")
FTP_USERNAME = os.getenv("FTP_USERNAME")
FTP_PASSWORD = os.getenv("FTP_PASSWORD")
REMOTE_FILENAME = os.getenv("REMOTE_FILENAME")
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)
rssi = wifi.radio.ap_info.rssi
pool = socketpool.SocketPool(wifi.radio)
print(f"Connect: {FTP_SERVER}:{FTP_PORT}")
sock = pool.socket()
sock.connect((FTP_SERVER, FTP_PORT)) # Підключення до FTP-сервера
print("\nUSER...")
sock.send(f"USER {FTP_USERNAME}\r\n".encode())
b = bytearray(512)
response = sock.recv_into(b, 512)
print(b.decode('ascii'))
print("\nPASS...")
b = bytearray(512)
sock.send(f"PASS {FTP_PASSWORD}\r\n".encode())
response = sock.recv_into(b, 512)
print(b.decode('ascii'))
b = bytearray(512)
sock.send(b"PASV\r\n")
response = sock.recv_into(b, 512)
response_str = b.decode('ascii')
print(response_str)
def send_all(sock, data):
total_sent = 0
while total_sent < len(data):
try:
sent = sock.send(data[total_sent:])
if sent == 0:
raise RuntimeError("socket connection broken")
total_sent += sent
except OSError as e:
if e.errno == errno.EAGAIN:
# Немає місця в буфері, треба почекати
time.sleep(0.01) # невелика пауза і спробувати знову
else:
raise # якщо інша помилка — підняти її
if "227 Entering Passive Mode" in response_str:
# Витягуємо IP і порт з відповіді
parts = response_str.split('(')[1].split(')')[0].split(',')
ip_address = ".".join(parts[:4])
port = int(parts[4]) * 256 + int(parts[5])
print(f"Data connection to {ip_address}:{port}")
data_sock = pool.socket()
data_sock.connect((ip_address, port))
print("\nSTOR...")
# Вивантажуємо файл
b = bytearray(512)
sock.send(f"STOR {REMOTE_FILENAME}\r\n".encode())
response = sock.recv_into(b, 512)
print(b.decode('ascii'))
print("\nSend image data...")
with open(REMOTE_FILENAME, "rb") as f:
while True:
chunk = f.read(512)
if not chunk:
break # кінець файлу
send_all(data_sock, chunk)
data_sock.close()
else:
print("Error: PASV command failed.")
print("\nQUIT...")
b = bytearray(512)
sock.send(b"QUIT\r\n")
response = sock.recv_into(b, 512)
print(b.decode('ascii'))
print("\nEnd")
sock.close()
Покладіть в корінь накопичувача будь який не порожній файл test.jpg
.
Код підключеться до FTP та завантажить файл. Можно використовувати для завантаження фотографій з камери або для вивантаження даних з датчика.