In this exercise, Raspberry Pi/Python3 act as socket server, ESP32/MicroPython
act as client connect to server via WiFi TCP. Once received, server
(Pi/Python) send a image (240x240) to client (ESP32/MicroPython), then the
client display the image on a 240*240 IPS (ST7789 SPI) LCD.
To make it more flexible, the image is in 240 batch of 240 pixel x 3 color (r,
g, b).
protocol:
Server | | Client
(Raspberry Pi/Python) | | (ESP32/MicroPython)
| |
Start | | Reset
| |
Setup as | |
socketserver.TCPServer | |
| |
| | Join the WiFi network
| | Connect to server with socket
| |
|<-- ACK ---| send ACK
send the 0th line |---------->| display the 0th line
|<-- ACK ---| send ACK
send the 1st line |---------->| display the 1st line
.
.
.
send the 239th line |---------->| display the 239th line
|<-- ACK ---| send ACK
close socket | | close socket
| |
wait next | | bye
Client side:
(ESP32/MicroPython)
The ESP32 used is a ESP32-DevKitC V4, display is a 240*240 IPS (ST7789 SPI) LCD. Library setup and connection, refer to former post "ESP32 (ESP32-DevKitC V4)/MicroPython + 240*240 IPS (ST7789 SPI) using russhughes/st7789py_mpy lib".
upyESP32_ImgClient_20210324c.py, MicroPython code run on ESP32. Modify ssid/password and serverIP for your WiFi network.from os import uname
from sys import implementation
import machine
import network
import socket
import ubinascii
import utime
import st7789py as st7789
from fonts import vga1_16x32 as font
import ustruct as struct
"""
ST7789 Display ESP32-DevKitC (SPI2)
SCL GPIO18
SDA GPIO23
GPIO19 (miso not used)
ST7789_rst GPIO5
ST7789_dc GPIO4
"""
#ST7789 use SPI(2)
st7789_res = 5
st7789_dc = 4
pin_st7789_res = machine.Pin(st7789_res, machine.Pin.OUT)
pin_st7789_dc = machine.Pin(st7789_dc, machine.Pin.OUT)
disp_width = 240
disp_height = 240
ssid = "your ssid"
password = "your password"
serverIP = '192.168.1.30'
serverPort = 9999
print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
spi2 = machine.SPI(2, baudrate=40000000, polarity=1)
print(spi2)
display = st7789.ST7789(spi2, disp_width, disp_width,
reset=pin_st7789_res,
dc=pin_st7789_dc,
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print("MAC: " + mac)
print()
#init ESP32 as STA
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
utime.sleep(1)
def do_connect():
global wlan
print('connect to network...')
display.fill(st7789.BLACK)
display.text(font, "connect...", 10, 10)
wlan.active(True)
if not wlan.isconnected():
print('...')
wlan.connect(ssid, password)
while not wlan.isconnected():
pass
print()
print('network config:')
print("interface's IP/netmask/gw/DNS addresses")
print(wlan.ifconfig())
display.fill(st7789.BLACK)
display.text(font, "connected", 10, 10)
def do_scan():
global wlan
print('scan network...')
wlan.active(True)
for network in wlan.scan():
print(network)
def do_connectServer():
global wlan
global display
addr = socket.getaddrinfo(serverIP, serverPort)[0][-1]
print(addr)
s = socket.socket()
s.connect(addr)
print('---')
display.fill(st7789.BLACK)
display.text(font, "waiting...", 10, 10)
print('Send ACK')
s.sendall(bytes("ACK","utf-8"))
display.set_window(0, 0, disp_width-1, disp_height-1)
pin_st7789_dc.on()
for j in range(disp_height):
buff = s.recv(disp_width*3)
for i in range(disp_width):
offset= i*3
spi2.write(struct.pack(st7789._ENCODE_PIXEL,
(buff[offset] & 0xf8) << 8 |
(buff[offset+1] & 0xfc) << 3 |
buff[offset+2] >> 3))
s.sendall(bytes("ACK","utf-8"))
s.close()
print('socket closed')
do_connect()
try:
do_connectServer()
except:
print('error')
display.text(font, "Error", 10, 200)
finally:
print('wlan.disconnect()')
wlan.disconnect()
print('\n- bye -')
Server Side:
(Raspberry Pi/Python)
The server will send Desktop/image.jpg with fixed resolution 240x240 (match with the display in client side). My former post "min. version of RPi/Python Code to control Camera Module with preview on local HDMI" is prepared for this purpose to capture using Raspberry Pi Camera Module .
pyMyTCP_ImgServer_20210324c.py, Python3 code run on Raspberry Pi.import socketserver
import platform
import matplotlib.image as mpimg
imageFile = '/home/pi/Desktop/image.jpg'
print("sys info:")
for info in platform.uname():
print(info)
class MyTCPHandler(socketserver.BaseRequestHandler):
#wait client response in 3 byte len
def wait_RESPONSE(self, client):
client.settimeout(10)
res = str()
data = client.recv(4)
return data.decode("utf-8")
def handle(self):
msocket = self.request
print("{} connected:".format(self.client_address[0]))
imgArray = mpimg.imread(imageFile)
self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
print('first RESPONSE received')
for j in range(240):
b = bytes(imgArray[j])
msocket.sendall(bytes(b))
self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
print('image sent finished')
msocket.close()
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
#with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
with socketserver.TCPServer(('', PORT), MyTCPHandler) as server:
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
This socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server example is
modify from
Python 3 socketserver.TCPServer Example. I assume socketserver.TCPServer will handle Ctrl-C with port close. But
in my test, SOMETIMES throw OSError of "Address already in use". In my practice,
try pressing Ctrl-C in REPL/restart repeatedly.
Next:
~ role reversed version: ESP32/MicroPython server + Raspberry Pi/Python client, transmit image via WiFi TCP socket.
No comments:
Post a Comment