85 lines
2.6 KiB
Python
85 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
|
|
DEFAULT_ENV = "seeed_xiao_esp32c3"
|
|
|
|
|
|
def find_pio():
|
|
pio = shutil.which("pio")
|
|
if pio:
|
|
return pio
|
|
candidate = Path.home() / ".platformio" / "penv" / "Scripts" / "pio.exe"
|
|
if candidate.exists():
|
|
return str(candidate)
|
|
candidate = Path.home() / ".platformio" / "penv" / "bin" / "pio"
|
|
if candidate.exists():
|
|
return str(candidate)
|
|
return "pio"
|
|
|
|
|
|
def run(command, cwd):
|
|
print("+ " + " ".join(command), flush=True)
|
|
subprocess.run(command, check=True, cwd=cwd)
|
|
|
|
|
|
def project_name(root):
|
|
app_h = root / "include" / "app.h"
|
|
if app_h.exists():
|
|
match = re.search(r'^\s*#define\s+PROJECT_NAME\s+"([^"]+)"', app_h.read_text(encoding="utf-8"), re.MULTILINE)
|
|
if match:
|
|
return match.group(1)
|
|
return root.name
|
|
|
|
|
|
def safe_filename_part(value):
|
|
value = value.strip().replace(" ", "-")
|
|
return re.sub(r"[^A-Za-z0-9._+-]+", "-", value).strip("-") or "project"
|
|
|
|
|
|
def package_timestamp():
|
|
return datetime.now().astimezone().isoformat(timespec="seconds").replace(":", "-")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Build firmware and LittleFS, then create a timestamped OTA update package.")
|
|
parser.add_argument("-e", "--environment", default=DEFAULT_ENV, help="PlatformIO environment to build.")
|
|
parser.add_argument("-o", "--output-dir", default="dist", help="Directory for the generated OTA package.")
|
|
parser.add_argument("--pio", default=find_pio(), help="Path to the PlatformIO executable.")
|
|
args = parser.parse_args()
|
|
|
|
root = Path(__file__).resolve().parent.parent
|
|
build_dir = root / ".pio" / "build" / args.environment
|
|
firmware = build_dir / "firmware.bin"
|
|
filesystem = build_dir / "littlefs.bin"
|
|
output_dir = (root / args.output_dir).resolve()
|
|
output = output_dir / f"{safe_filename_part(project_name(root))}_{package_timestamp()}.tslpkg"
|
|
|
|
try:
|
|
run([args.pio, "run", "-e", args.environment, "-t", "buildfs"], root)
|
|
run([args.pio, "run", "-e", args.environment], root)
|
|
run([
|
|
sys.executable,
|
|
str(Path(__file__).resolve().parent / "create_update_package.py"),
|
|
"--firmware",
|
|
str(firmware),
|
|
"--filesystem",
|
|
str(filesystem),
|
|
"--output",
|
|
str(output),
|
|
], root)
|
|
except subprocess.CalledProcessError as error:
|
|
sys.exit(error.returncode)
|
|
|
|
print(f"OTA update file: {output.resolve()}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|