Implement shutdown and reboot via API; add Makefile for deployment
This commit is contained in:
parent
56e7a1d2de
commit
f16f506332
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
# General
|
||||
/_tmp
|
||||
/.upload_cache
|
||||
|
||||
# Python
|
||||
__pycache__
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
# Configuration
|
||||
LIGHTBAR_HOST ?= 192.168.17.22
|
||||
LIGHTBAR_URL := http://$(LIGHTBAR_HOST)
|
||||
WEBREPL_CLI := webrepl_cli.py
|
||||
WEBREPL_HOST := $(LIGHTBAR_HOST)
|
||||
WEBREPL_PASSWORD ?= acab
|
||||
REPL_TTY_PATH ?= /dev/ttyUSB0
|
||||
|
||||
# Directory for saving timestamps of when files were last uploaded
|
||||
UPLOAD_CACHE_DIR := .upload_cache
|
||||
|
||||
# Auto-detect all .py files that should be uploaded
|
||||
SRC_UPLOAD_TARGETS := $(patsubst %.py,$(UPLOAD_CACHE_DIR)/%.py.timestamp,$(wildcard src/*.py src/**/*.py))
|
||||
LIB_UPLOAD_TARGETS := $(patsubst %.py,$(UPLOAD_CACHE_DIR)/%.py.timestamp,$(wildcard lib/*.py))
|
||||
|
||||
# Default target
|
||||
.DEFAULT_GOAL := upload-reboot
|
||||
|
||||
# -- Device control
|
||||
|
||||
# Reboot the ESP32 via REST API
|
||||
.PHONY: reboot
|
||||
reboot:
|
||||
curl -X POST $(LIGHTBAR_URL)/api/reboot
|
||||
|
||||
# Shutdown the HTTP server via REST API, allowing access to the WebREPL
|
||||
.PHONY: shutdown
|
||||
shutdown:
|
||||
curl -X POST $(LIGHTBAR_URL)/api/shutdown
|
||||
|
||||
# -- Deployment
|
||||
|
||||
# Upload all files (or only /src, or only /lib) to the ESP32 via WebREPL
|
||||
.PHONY: upload upload-all upload-src upload-lib
|
||||
upload: upload-all
|
||||
upload-all: upload-src upload-lib
|
||||
upload-src: $(SRC_UPLOAD_TARGETS)
|
||||
upload-lib: $(LIB_UPLOAD_TARGETS)
|
||||
|
||||
# Upload all files via WebREPL and reboot
|
||||
.PHONY: upload-reboot
|
||||
upload-reboot: upload-all reboot
|
||||
|
||||
# Pattern rules for uploading files to the ESP32 via WebREPL if they were changed since the last upload
|
||||
$(UPLOAD_CACHE_DIR)/%.py.timestamp :: %.py
|
||||
$(WEBREPL_CLI) -p $(WEBREPL_PASSWORD) $*.py $(WEBREPL_HOST):/$(subst src/,,$*).py >/dev/null
|
||||
@mkdir -p $(@D) && touch $@
|
||||
|
||||
# Create necessary directories on the ESP32 filesystem via REPL (not WebREPL!)
|
||||
# TODO: This cannot be done via webrepl_cli.py, so you either need to use REPL over USB, or create the directories manually
|
||||
.PHONY: repl-create-directories
|
||||
repl-create-directories:
|
||||
@echo "(Note: If the directory already exists, rshell will print \"Unable to create [DIR]\")"
|
||||
@echo
|
||||
rshell -p $(REPL_TTY_PATH) mkdir /pyboard/lib /pyboard/lightbar
|
||||
|
||||
# Clear the .upload_cache directory that contains the last upload timestamps
|
||||
.PHONY: clear-upload-cache clear-upload-cache-src
|
||||
clear-upload-cache-all:
|
||||
rm -rf $(UPLOAD_CACHE_DIR)
|
||||
clear-upload-cache-src:
|
||||
rm -rf $(UPLOAD_CACHE_DIR)/src/
|
||||
|
||||
# Clear the upload timestamp cache and re-upload all files
|
||||
.PHONY: reupload-all reupload-src
|
||||
reupload-all: clear-upload-cache-all upload-all
|
||||
reupload-src: clear-upload-cache-src upload-src
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# Example file for WebREPL configuration. Copy to src/webrepl_cfg.py, adjust and upload to the board.
|
||||
|
||||
# Define the password for WebREPL here
|
||||
PASS = 'ultra-secret-webrepl-password'
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Example file for WLAN configuration. Copy to wlan_cfg.py and adjust!
|
||||
# Example file for WLAN configuration. Copy to src/wlan_cfg.py, adjust and upload to the board.
|
||||
SSID = 'Example SSID'
|
||||
PASSWORD = 'ultra secret wlan password'
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import machine
|
||||
import uasyncio
|
||||
from microdot_asyncio import Microdot
|
||||
|
||||
from lightbar.frontend import frontend
|
||||
from lightbar.rest_api import rest_api
|
||||
|
||||
|
||||
class Lightbar(Microdot):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.mount(frontend)
|
||||
self.mount(rest_api, url_prefix='/api')
|
||||
|
||||
async def scheduled_shutdown(self):
|
||||
await uasyncio.sleep(0.1)
|
||||
self.shutdown()
|
||||
|
||||
@staticmethod
|
||||
async def scheduled_reboot():
|
||||
await uasyncio.sleep(0.1)
|
||||
machine.reset()
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from microdot_asyncio import Microdot
|
||||
|
||||
frontend = Microdot()
|
||||
|
||||
|
||||
@frontend.get('')
|
||||
async def handle_index(_request):
|
||||
return 'Meow, world :3\n'
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import uasyncio
|
||||
from microdot_asyncio import Microdot
|
||||
|
||||
rest_api = Microdot()
|
||||
|
||||
|
||||
# TODO -- all of these responses aren't REST yet
|
||||
@rest_api.post('/shutdown')
|
||||
async def shutdown(request):
|
||||
uasyncio.create_task(request.app.scheduled_shutdown())
|
||||
return 'Shutting down!\n'
|
||||
|
||||
|
||||
@rest_api.post('/reboot')
|
||||
async def reboot(request):
|
||||
uasyncio.create_task(request.app.scheduled_reboot())
|
||||
return 'Rebooting now!\n'
|
||||
15
src/main.py
15
src/main.py
|
|
@ -1,12 +1,5 @@
|
|||
from microdot_asyncio import Microdot
|
||||
from lightbar.app import Lightbar
|
||||
|
||||
app = Microdot()
|
||||
|
||||
|
||||
@app.route('/')
|
||||
async def index(request):
|
||||
return 'Meow, world\n'
|
||||
|
||||
|
||||
print('[main] Running Microdot app...')
|
||||
app.run(port=80)
|
||||
print('[main] Starting lightbar HTTP server...')
|
||||
api_server = Lightbar()
|
||||
api_server.run(port=80, debug=True)
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
# Define the password for WebREPL here
|
||||
PASS = 'ultra-secret-webrepl-password'
|
||||
Loading…
Reference in New Issue