feat: update code and build script for circuitpython 8.1.0
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
build
|
||||
*.uf2
|
||||
mpy-cross*
|
||||
adafruit-circuitpython-bundle*
|
||||
|
||||
22
build.py
Normal file → Executable file
22
build.py
Normal file → Executable file
@@ -1,16 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Builder script to compile .py files to .mpy bytecode using mpy-cross
|
||||
"""
|
||||
|
||||
import glob
|
||||
from subprocess import PIPE, Popen
|
||||
from errno import ENOTDIR
|
||||
from os import listdir, makedirs
|
||||
from os.path import join, splitext
|
||||
from shutil import copytree, copy, rmtree
|
||||
from errno import ENOTDIR
|
||||
from shutil import copy, copytree, rmtree
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
SRC = 'src'
|
||||
DST = 'build'
|
||||
SRC = "src"
|
||||
DST = "build"
|
||||
|
||||
|
||||
def recursive_copy(src: str, dst: str):
|
||||
@@ -58,20 +59,21 @@ def main():
|
||||
# Remove the build directory if it exists, then create it again
|
||||
rmtree(DST, ignore_errors=True)
|
||||
makedirs(DST, exist_ok=True)
|
||||
makedirs(join(DST, "lib"), exist_ok=True)
|
||||
|
||||
# Find the path of the mpy-cross binary
|
||||
# Find the path of the mpy-cross binary
|
||||
mpy_cross_bin = join(".", glob.glob("mpy-cross.static*")[0])
|
||||
|
||||
# Process each entry in the source directory
|
||||
# Process each entry in the source directory
|
||||
for entry in listdir(SRC):
|
||||
src_path = join(SRC, entry)
|
||||
# If the entry is a Python source file that needs to be compiled
|
||||
if name := to_compile(entry):
|
||||
|
||||
# Compile the file using mpy-cross
|
||||
with Popen(
|
||||
[mpy_cross_bin, "-o", join(DST, f"{name}.mpy"), src_path],
|
||||
stdout=PIPE,
|
||||
[mpy_cross_bin, "-o",
|
||||
join(DST, "lib", f"{name}.mpy"), src_path],
|
||||
stdout=PIPE,
|
||||
) as process:
|
||||
process.communicate()
|
||||
else:
|
||||
|
||||
15
src/api.py
15
src/api.py
@@ -1,9 +1,10 @@
|
||||
"""
|
||||
Handler code to interact with the backend for each incoming web request
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
|
||||
from adafruit_httpserver import JSONResponse, Request
|
||||
|
||||
import logs
|
||||
from ducky import run_script, run_script_file
|
||||
|
||||
@@ -16,25 +17,24 @@ def create(path, contents=b""):
|
||||
file.write(contents)
|
||||
|
||||
|
||||
def handle(body, response):
|
||||
def handle(request: Request):
|
||||
"""
|
||||
Handle all the API requests from the web interface like
|
||||
create, load, store, delete and run.
|
||||
"""
|
||||
body = request.json()
|
||||
action = body["action"]
|
||||
if action == "list":
|
||||
response.send(json.dumps(os.listdir("payloads")))
|
||||
return
|
||||
return JSONResponse(request, os.listdir("payloads"))
|
||||
|
||||
if action == "logs":
|
||||
response.send(logs.consume())
|
||||
return
|
||||
return JSONResponse(request, logs.consume())
|
||||
|
||||
filename = body.get("filename")
|
||||
path = f"payloads/{filename}"
|
||||
if action == "load":
|
||||
with open(path) as file:
|
||||
response.send(json.dumps({"contents": file.read()}))
|
||||
return JSONResponse(request, {"contents": file.read()})
|
||||
elif action == "store":
|
||||
create(path, body["contents"].encode())
|
||||
elif action == "delete":
|
||||
@@ -46,3 +46,4 @@ def handle(body, response):
|
||||
run_script_file(path)
|
||||
elif contents := body["contents"]:
|
||||
run_script(contents)
|
||||
return JSONResponse(request, {})
|
||||
|
||||
31
src/code.py
31
src/code.py
@@ -3,17 +3,12 @@ The entrypoint for our circuitpython board.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
|
||||
import microcontroller
|
||||
import socketpool
|
||||
import wifi
|
||||
from adafruit_httpserver.methods import HTTPMethod
|
||||
from adafruit_httpserver.mime_type import MIMEType
|
||||
from adafruit_httpserver.request import HTTPRequest
|
||||
from adafruit_httpserver.response import HTTPResponse
|
||||
from adafruit_httpserver.server import HTTPServer
|
||||
from adafruit_httpserver import POST, FileResponse, Request, Server
|
||||
|
||||
from api import handle
|
||||
|
||||
@@ -28,27 +23,23 @@ async def main():
|
||||
"""
|
||||
wifi.radio.start_ap(ssid=os.getenv("SSID"), password=os.getenv("PASSWORD"))
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
server = HTTPServer(pool)
|
||||
server = Server(pool)
|
||||
|
||||
@server.route("/")
|
||||
def base(request: HTTPRequest):
|
||||
with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
|
||||
response.send_file("static/index.html")
|
||||
def base(request: Request):
|
||||
return FileResponse(request, "index.html", root_path="/static")
|
||||
|
||||
@server.route("/main.css")
|
||||
def css(request: HTTPRequest):
|
||||
with HTTPResponse(request, content_type=MIMEType.TYPE_CSS) as response:
|
||||
response.send_file("static/main.css")
|
||||
def css(request: Request):
|
||||
return FileResponse(request, "main.css", root_path="/static")
|
||||
|
||||
@server.route("/script.js")
|
||||
def javascript(request: HTTPRequest):
|
||||
with HTTPResponse(request, content_type=MIMEType.TYPE_JS) as response:
|
||||
response.send_file("static/script.js")
|
||||
def javascript(request: Request):
|
||||
return FileResponse(request, "script.js", root_path="/static")
|
||||
|
||||
@server.route("/api", HTTPMethod.POST)
|
||||
def api(request: HTTPRequest):
|
||||
with HTTPResponse(request, content_type=MIMEType.TYPE_JSON) as response:
|
||||
handle(json.loads(request.body), response)
|
||||
@server.route("/api", POST)
|
||||
def api(request: Request):
|
||||
return handle(request)
|
||||
|
||||
server.serve_forever(str(wifi.radio.ipv4_address_ap))
|
||||
|
||||
|
||||
@@ -54,15 +54,14 @@ def press_keys(line: str):
|
||||
Really useful for keyboard shortcuts like Meta+R.
|
||||
"""
|
||||
# loop on each key filtering empty values
|
||||
for key in filter(None, line.split(" ")):
|
||||
key = key.upper()
|
||||
for key in filter(None, line.upper().split(" ")):
|
||||
if command_keycode := Keycode.__dict__.get(key):
|
||||
# If this is a valid key, send its keycode
|
||||
kbd.press(command_keycode)
|
||||
continue
|
||||
# If it's not a known key name, log it for diagnosis
|
||||
warn(f"unknown key: <{key}>")
|
||||
kbd.release_all()
|
||||
kbd.release_all()
|
||||
|
||||
|
||||
def repeat(contents: str, times: int):
|
||||
@@ -98,7 +97,7 @@ def run_script(contents):
|
||||
elif path := after("IMPORT"):
|
||||
run_script_file(path)
|
||||
elif millis := after("DEFAULT_DELAY", "DEFAULTDELAY"):
|
||||
default_delay = int(millis) * 10
|
||||
default_delay = int(millis)
|
||||
elif after("LED") is not None:
|
||||
LED.value ^= True
|
||||
elif string := after("STRING"):
|
||||
|
||||
@@ -3,8 +3,6 @@ A very bare-bones logging implementation
|
||||
for the bottom pane of the Web UI.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
logs = []
|
||||
|
||||
|
||||
@@ -13,7 +11,7 @@ def consume() -> str:
|
||||
Convert all the log entries from the module's global mutable
|
||||
list to json return them, clearing the list after the dump.
|
||||
"""
|
||||
dump = json.dumps(logs)
|
||||
dump = logs.copy()
|
||||
logs.clear()
|
||||
return dump
|
||||
|
||||
|
||||
Reference in New Issue
Block a user