MicroPython stuff
This commit is contained in:
parent
a8e26be242
commit
60ba2c59e7
2
code/MicroPython/.gitignore
vendored
Normal file
2
code/MicroPython/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
microdot/
|
||||
utemplate/
|
37
code/MicroPython/README.md
Normal file
37
code/MicroPython/README.md
Normal file
@ -0,0 +1,37 @@
|
||||
#
|
||||
|
||||
##
|
||||
|
||||
```shell
|
||||
# ...
|
||||
esptool.py --port /dev/ttyACM0 erase_flash
|
||||
# ...
|
||||
esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 ~/Downloads/LOLIN_S2_MINI-20240222-v1.22.2.bin
|
||||
```
|
||||
|
||||
```shell
|
||||
pip3 install rshell #
|
||||
pip3 install mpremote #
|
||||
```
|
||||
|
||||
### Выполнение кода
|
||||
|
||||
```shell
|
||||
rshell --port /dev/ttyACM0 cat blink.py
|
||||
```
|
||||
|
||||
```python
|
||||
import machine
|
||||
import time
|
||||
|
||||
led = machine.Pin(15, machine.Pin.OUT)
|
||||
|
||||
led.on()
|
||||
time.sleep(1)
|
||||
led.off()
|
||||
time.sleep(1)
|
||||
```
|
||||
|
||||
```shell
|
||||
mpremote exec 'exec(open("blink.py").read())'
|
||||
```
|
9
code/MicroPython/blink.py
Normal file
9
code/MicroPython/blink.py
Normal file
@ -0,0 +1,9 @@
|
||||
import machine
|
||||
import time
|
||||
|
||||
led = machine.Pin(15, machine.Pin.OUT)
|
||||
|
||||
led.on()
|
||||
time.sleep(1)
|
||||
led.off()
|
||||
time.sleep(1)
|
4
code/MicroPython/boot.py
Normal file
4
code/MicroPython/boot.py
Normal file
@ -0,0 +1,4 @@
|
||||
"""
|
||||
Скрипт, который выполняется при старте EPS32.
|
||||
После него выполняется скрипт `main.py`.
|
||||
"""
|
163
code/MicroPython/ftp.py
Normal file
163
code/MicroPython/ftp.py
Normal file
@ -0,0 +1,163 @@
|
||||
import socket
|
||||
import network
|
||||
import os
|
||||
import _thread
|
||||
|
||||
DATA_PORT = 13333
|
||||
|
||||
ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
ftpsocket.bind(socket.getaddrinfo("0.0.0.0", 21)[0][4])
|
||||
datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4])
|
||||
|
||||
ftpsocket.listen(1)
|
||||
datasocket.listen(1)
|
||||
datasocket.settimeout(10)
|
||||
|
||||
dataclient = None
|
||||
|
||||
|
||||
def send_list_data(cwd, dataclient):
|
||||
for file in os.listdir(cwd):
|
||||
stat = os.stat(get_absolute_path(cwd, file))
|
||||
file_permissions = "drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--"
|
||||
file_size = stat[6]
|
||||
description = "{} 1 owner group {:>13} Jan 1 1980 {}\r\n".format(
|
||||
file_permissions, file_size, file
|
||||
)
|
||||
dataclient.sendall(description)
|
||||
|
||||
|
||||
def send_file_data(path, dataclient):
|
||||
with open(path) as file:
|
||||
chunk = file.read(128)
|
||||
while len(chunk) > 0:
|
||||
dataclient.sendall(chunk)
|
||||
chunk = file.read(128)
|
||||
|
||||
|
||||
def save_file_data(path, dataclient):
|
||||
with open(path, "w") as file:
|
||||
chunk = dataclient.read(128)
|
||||
while len(chunk) > 0:
|
||||
file.write(chunk)
|
||||
chunk = dataclient.read(128)
|
||||
|
||||
|
||||
def get_absolute_path(cwd, payload):
|
||||
# if it doesn't start with / consider
|
||||
# it a relative path
|
||||
if not payload.startswith("/"):
|
||||
payload = cwd + "/" + payload
|
||||
# and don't leave any trailing /
|
||||
return payload.rstrip("/")
|
||||
|
||||
|
||||
def ftp():
|
||||
try:
|
||||
dataclient = None
|
||||
while True:
|
||||
cwd = "/"
|
||||
cl, remote_addr = ftpsocket.accept()
|
||||
cl.settimeout(300)
|
||||
try:
|
||||
print("FTP connection from:", remote_addr)
|
||||
cl.sendall("220 Hello, this is the ESP8266.\r\n")
|
||||
while True:
|
||||
data = cl.readline().decode("utf-8").replace("\r\n", "")
|
||||
if len(data) <= 0:
|
||||
print("Client is dead")
|
||||
break
|
||||
|
||||
command, payload = (data.split(" ") + [""])[:2]
|
||||
command = command.upper()
|
||||
|
||||
print("Command={}, Payload={}".format(command, payload))
|
||||
|
||||
if command == "USER":
|
||||
cl.sendall("230 Logged in.\r\n")
|
||||
elif command == "SYST":
|
||||
cl.sendall("215 ESP8266 MicroPython\r\n")
|
||||
elif command == "SYST":
|
||||
cl.sendall("502\r\n")
|
||||
elif command == "PWD":
|
||||
cl.sendall('257 "{}"\r\n'.format(cwd))
|
||||
elif command == "CWD":
|
||||
path = get_absolute_path(cwd, payload)
|
||||
try:
|
||||
files = os.listdir(path)
|
||||
cwd = path
|
||||
cl.sendall('250 Directory changed successfully\r\n')
|
||||
except:
|
||||
cl.sendall('550 Failed to change directory\r\n')
|
||||
elif command == "EPSV":
|
||||
cl.sendall('502\r\n')
|
||||
elif command == "TYPE":
|
||||
# probably should switch between binary and not
|
||||
cl.sendall('200 Transfer mode set\r\n')
|
||||
elif command == "SIZE":
|
||||
path = get_absolute_path(cwd, payload)
|
||||
try:
|
||||
size = os.stat(path)[6]
|
||||
cl.sendall('213 {}\r\n'.format(size))
|
||||
except:
|
||||
cl.sendall('550 Could not get file size\r\n')
|
||||
elif command == "QUIT":
|
||||
cl.sendall('221 Bye.\r\n')
|
||||
elif command == "PASV":
|
||||
addr = network.WLAN().ifconfig()[0]
|
||||
cl.sendall(
|
||||
'227 Entering Passive Mode ({},{},{}).\r\n'.format(
|
||||
addr.replace('.', ','), DATA_PORT >> 8, DATA_PORT % 256
|
||||
)
|
||||
)
|
||||
dataclient, data_addr = datasocket.accept()
|
||||
print("FTP Data connection from:", data_addr)
|
||||
elif command == "LIST":
|
||||
try:
|
||||
send_list_data(cwd, dataclient)
|
||||
dataclient.close()
|
||||
cl.sendall("150 Here comes the directory listing.\r\n")
|
||||
cl.sendall("226 Listed.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Failed to list directory\r\n')
|
||||
finally:
|
||||
dataclient.close()
|
||||
elif command == "RETR":
|
||||
try:
|
||||
send_file_data(get_absolute_path(cwd, payload), dataclient)
|
||||
dataclient.close()
|
||||
cl.sendall("150 Opening data connection.\r\n")
|
||||
cl.sendall("226 Transfer complete.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Failed to send file\r\n')
|
||||
finally:
|
||||
dataclient.close()
|
||||
elif command == "STOR":
|
||||
try:
|
||||
cl.sendall("150 Ok to send data.\r\n")
|
||||
save_file_data(get_absolute_path(cwd, payload), dataclient)
|
||||
dataclient.close()
|
||||
cl.sendall("226 Transfer complete.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Failed to send file\r\n')
|
||||
finally:
|
||||
dataclient.close()
|
||||
else:
|
||||
cl.sendall("502 Unsupported command.\r\n")
|
||||
print("Unsupported command {} with payload {}".format(command, payload))
|
||||
|
||||
finally:
|
||||
cl.close()
|
||||
finally:
|
||||
datasocket.close()
|
||||
ftpsocket.close()
|
||||
if dataclient is not None:
|
||||
dataclient.close()
|
||||
|
||||
|
||||
_thread.start_new_thread(ftp, ())
|
13
code/MicroPython/get_mac.py
Normal file
13
code/MicroPython/get_mac.py
Normal file
@ -0,0 +1,13 @@
|
||||
"""
|
||||
Скрипт, который возвращает MAC адрес
|
||||
|
||||
https://git.a2s.su/iiiypuk/snipplets.dev/src/branch/master/code/MicroPython
|
||||
Update: May 14 2024
|
||||
"""
|
||||
|
||||
import network
|
||||
import ubinascii
|
||||
|
||||
mac = ubinascii.hexlify(network.WLAN().config('mac'), ':').decode()
|
||||
|
||||
print(mac)
|
79
code/MicroPython/http.py
Normal file
79
code/MicroPython/http.py
Normal file
@ -0,0 +1,79 @@
|
||||
import machine
|
||||
import time
|
||||
import gc
|
||||
|
||||
from microdot import Microdot, send_file, Request, Response
|
||||
|
||||
from microdot.utemplate import Template
|
||||
|
||||
led = machine.Pin(15, machine.Pin.OUT)
|
||||
|
||||
app = Microdot()
|
||||
Response.default_content_type = 'text/html'
|
||||
Request.max_content_length = 1024 * 1024
|
||||
|
||||
|
||||
def cmd_parse(method, args):
|
||||
if method == 'GET':
|
||||
if 'cmd' in args:
|
||||
cmd = args['cmd']
|
||||
|
||||
if 'reboot' == cmd:
|
||||
for x in range(2):
|
||||
led.on()
|
||||
time.sleep_ms(200)
|
||||
led.off()
|
||||
time.sleep_ms(200)
|
||||
|
||||
machine.reset()
|
||||
|
||||
if 'ftp' == cmd:
|
||||
exec(open('ftp.py').read())
|
||||
|
||||
|
||||
@app.route('/static/<path:path>')
|
||||
async def static(request, path):
|
||||
if '..' in path:
|
||||
# directory traversal is not allowed
|
||||
return 'Not found', 404
|
||||
return send_file('static/' + path)
|
||||
|
||||
|
||||
@app.get('/file')
|
||||
async def file(request):
|
||||
return send_file('templates/upload.html')
|
||||
|
||||
|
||||
@app.post('/upload')
|
||||
async def upload(request):
|
||||
filename = request.headers['Content-Disposition'].split('filename=')[1].strip('"')
|
||||
size = int(request.headers['Content-Length'])
|
||||
|
||||
filename = filename.replace('/', '_')
|
||||
|
||||
with open('/' + filename, 'wb') as f:
|
||||
while size > 0:
|
||||
chunk = await request.stream.read(min(size, 1024))
|
||||
f.write(chunk)
|
||||
size -= len(chunk)
|
||||
|
||||
print('Successfully saved file: ' + filename)
|
||||
return ''
|
||||
|
||||
|
||||
@app.route('/')
|
||||
async def index(request):
|
||||
# print(request.args, request.path, request.method, sep='\n')
|
||||
# print(request.url, request.query_string, request.url_args, sep='\n')
|
||||
print(request.args)
|
||||
|
||||
cmd_parse(request.method, request.args)
|
||||
|
||||
ram_f = gc.mem_free()
|
||||
ram_a = gc.mem_alloc()
|
||||
ram_t = ram_a + ram_f
|
||||
return Template('index.html').render(ram_free=int(ram_f / 1024), ram_total=int(ram_t / 1024))
|
||||
|
||||
|
||||
print('HTTP server started')
|
||||
app.run(port=80)
|
17
code/MicroPython/main.py
Normal file
17
code/MicroPython/main.py
Normal file
@ -0,0 +1,17 @@
|
||||
"""
|
||||
Скрипт, который выполняется при старте EPS32.
|
||||
После выполнения скрипта `boot.py`.
|
||||
"""
|
||||
|
||||
import time
|
||||
import network_ap
|
||||
import network_sta
|
||||
|
||||
# Connecting to Wifi
|
||||
wifi_connect = network_sta.connect('Keenetic-8647', 'sFJZi7U51')
|
||||
if wifi_connect == False:
|
||||
wifi_connect = network_ap.connect(essid='SkyNet', clients=2)
|
||||
|
||||
# If WiFi connected run HTTP server
|
||||
if wifi_connect == True:
|
||||
exec(open('http.py').read())
|
21
code/MicroPython/network_ap.py
Normal file
21
code/MicroPython/network_ap.py
Normal file
@ -0,0 +1,21 @@
|
||||
import time
|
||||
import network
|
||||
|
||||
|
||||
def connect(essid='ESP', clients=3) -> bool:
|
||||
print('Starting AP: {0}...'.format(essid))
|
||||
ap = network.WLAN(network.AP_IF)
|
||||
ap.active(True)
|
||||
ap.config(essid=essid)
|
||||
ap.config(max_clients=clients)
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
if ap.isconnected():
|
||||
print('AP "{0}" started'.format(essid))
|
||||
|
||||
return True
|
||||
else:
|
||||
print('Starting AP failed!')
|
||||
|
||||
return False
|
38
code/MicroPython/network_sta.py
Normal file
38
code/MicroPython/network_sta.py
Normal file
@ -0,0 +1,38 @@
|
||||
import time
|
||||
import network
|
||||
|
||||
|
||||
def connect(ssid: str, password: str) -> bool:
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
wlan.config(reconnects=2)
|
||||
|
||||
if not wlan.isconnected():
|
||||
print('Scanning networks...')
|
||||
wlan.scan()
|
||||
print('Connecting to {0}...'.format(ssid))
|
||||
# try:
|
||||
wlan.connect(ssid, password)
|
||||
|
||||
while not wlan.isconnected():
|
||||
status = wlan.status()
|
||||
if status in (network.STAT_IDLE, network.STAT_WRONG_PASSWORD, network.STAT_NO_AP_FOUND):
|
||||
print('\nConnection to "{0}" failed!'.format(ssid))
|
||||
wlan.active(False)
|
||||
|
||||
return False
|
||||
|
||||
print('.', end='')
|
||||
time.sleep(0.1)
|
||||
|
||||
print('\nConnection success!')
|
||||
ifconfig = wlan.ifconfig()
|
||||
print('IP: {0}'.format(ifconfig[0]))
|
||||
|
||||
return True
|
||||
else:
|
||||
print('Already connected!')
|
||||
ifconfig = wlan.ifconfig()
|
||||
print('IP: {0}'.format(ifconfig[0]))
|
||||
|
||||
return True
|
3
code/MicroPython/pyproject.toml
Normal file
3
code/MicroPython/pyproject.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[tool.black]
|
||||
skip-string-normalization = true
|
||||
line-length = 100
|
13
code/MicroPython/read_write_file.py
Normal file
13
code/MicroPython/read_write_file.py
Normal file
@ -0,0 +1,13 @@
|
||||
import os
|
||||
|
||||
print('Listing filesystem...')
|
||||
print(os.listdir(), '\n')
|
||||
|
||||
print('Write data...')
|
||||
with open('data.txt', 'w') as f:
|
||||
count = f.write('ololo\n')
|
||||
print('Write', count, 'bytes')
|
||||
|
||||
print('Read data...')
|
||||
with open('data.txt', 'r') as f:
|
||||
print('Data:', f.read())
|
3
code/MicroPython/static/styles.css
Normal file
3
code/MicroPython/static/styles.css
Normal file
@ -0,0 +1,3 @@
|
||||
body {
|
||||
background-color: #ccc;
|
||||
}
|
18
code/MicroPython/templates/index.html
Normal file
18
code/MicroPython/templates/index.html
Normal file
@ -0,0 +1,18 @@
|
||||
{% args ram_free, ram_total %}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>S2F Terminal</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link href="/static/styles.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<h1>by Alexander Popov</h1>
|
||||
<p>Free RAM: {{ ram_free }} of {{ ram_total }}</p>
|
||||
<div>
|
||||
<a href="/?cmd=ftp">Поднять FTP сервер</a><br>
|
||||
<a href="/?cmd=reboot">Перезапустить</a><br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
23
code/MicroPython/templates/index_html.py
Normal file
23
code/MicroPython/templates/index_html.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Autogenerated file
|
||||
def render(ram_free, ram_total):
|
||||
yield """<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>S2F Terminal</title>
|
||||
<meta charset=\"utf-8\">
|
||||
<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">
|
||||
<link href=\"/static/styles.css\" rel=\"stylesheet\">
|
||||
</head>
|
||||
<body>
|
||||
<h1>by Alexander Popov</h1>
|
||||
<p>Free RAM: """
|
||||
yield str(ram_free)
|
||||
yield """ of """
|
||||
yield str(ram_total)
|
||||
yield """</p>
|
||||
<div>
|
||||
<a href=\"/?cmd=ftp\">Поднять FTP сервер</a><br>
|
||||
<a href=\"/?cmd=reboot\">Перезапустить</a><br>
|
||||
</div>
|
||||
</body>
|
||||
</html>"""
|
35
code/MicroPython/templates/upload.html
Normal file
35
code/MicroPython/templates/upload.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Microdot Upload Example</title>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Microdot Upload Example</h1>
|
||||
<form id="form">
|
||||
<input type="file" id="file" name="file" />
|
||||
<input type="submit" value="Upload" />
|
||||
</form>
|
||||
<script>
|
||||
async function upload(ev) {
|
||||
ev.preventDefault();
|
||||
const file = document.getElementById('file').files[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
await fetch('/upload', {
|
||||
method: 'POST',
|
||||
body: file,
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Disposition': `attachment; filename="${file.name}"`,
|
||||
},
|
||||
}).then(res => {
|
||||
console.log('Upload accepted');
|
||||
window.location.href = '/';
|
||||
});
|
||||
}
|
||||
document.getElementById('form').addEventListener('submit', upload);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
0
code/MicroPython/webrepl_cfg.py
Normal file
0
code/MicroPython/webrepl_cfg.py
Normal file
Loading…
Reference in New Issue
Block a user