Публікація

Завантаження зображення на 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 та завантажить файл. Можно використовувати для завантаження фотографій з камери або для вивантаження даних з датчика.

Публікація захищена ліцензією CC BY 4.0 .