From 1844a2e4c5dfae4f41df488f87b82f83ed770a8b Mon Sep 17 00:00:00 2001 From: Pi User Date: Wed, 1 Oct 2025 21:34:29 +1300 Subject: [PATCH] Update SPI JSON sender to led-bar format: {"settings":{...}, "save":false} and tooling scripts --- test/send_json.py | 88 ++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/test/send_json.py b/test/send_json.py index fb9089b..994b13c 100755 --- a/test/send_json.py +++ b/test/send_json.py @@ -3,9 +3,9 @@ CLI to send JSON over SPI to the ESP32-C3 SPI slave. Examples: - ./send_json.py --data '{"d":{"t":"b","br":128},"bar":{"pt":"off"}}' + ./send_json.py --data '{"settings":{"pattern":"on","brightness":128}}' ./send_json.py --file payload.json - ./send_json.py --beat --brightness 180 --delay 30 --pattern wave + ./send_json.py --brightness 180 --delay 30 --pattern wave """ import argparse @@ -22,7 +22,12 @@ from spi_master_test import SPIMasterTest # noqa: E402 def build_payload_from_args(args: argparse.Namespace) -> dict: - """Build a control payload matching the receiver format from args.""" + """Build a control payload matching led-bar's receiver format from args. + + Format: + {"settings": { ... }, "save": false} + Or raw passthrough if --data/--file is provided. + """ if args.data: try: return json.loads(args.data) @@ -38,56 +43,67 @@ def build_payload_from_args(args: argparse.Namespace) -> dict: print(f"Failed to read JSON file {args.file}: {exc}") sys.exit(2) - # Build from individual params (beat or update) - msg_type = "b" if args.beat else "u" - defaults = {"t": msg_type} - if args.brightness is not None: - defaults["br"] = int(args.brightness) - if args.delay is not None: - defaults["dl"] = int(args.delay) - if args.n1 is not None: - defaults["n1"] = int(args.n1) - if args.n2 is not None: - defaults["n2"] = int(args.n2) - if args.n3 is not None: - defaults["n3"] = int(args.n3) - if args.step is not None: - defaults["s"] = int(args.step) + # Build led-bar settings object + settings: dict = {} - bar = {} if args.pattern: - bar["pt"] = args.pattern + settings["pattern"] = args.pattern + if args.brightness is not None: + settings["brightness"] = int(args.brightness) + if args.delay is not None: + settings["delay"] = int(args.delay) + + # Optional numeric params if supported on led-bar side + if args.n1 is not None: + settings["n1"] = int(args.n1) + if args.n2 is not None: + settings["n2"] = int(args.n2) + if args.n3 is not None: + settings["n3"] = int(args.n3) + + payload: dict = {"settings": settings} + + # Optional: step tick control + if args.step is not None: + payload["step"] = int(args.step) + + # Allow override raw NAME JSON into settings directly if provided if args.name_value: - # Allow sending a specific bar (device) override by name - # Usage: --name-value mybar '{"br":200,"pt":"off"}' try: name, value = args.name_value - bar = json.loads(value) - return {"d": defaults, name: bar} + override = json.loads(value) + # Merge override fields into settings + if not isinstance(override, dict): + raise ValueError("--name-value JSON must be an object") + settings.update(override) except Exception as exc: print(f"Invalid --name-value: {exc}") sys.exit(2) - # Default field name could be populated on receiver side via settings.get("name") - # We only send defaults and a generic "bar" override here for convenience. - return {"d": defaults, "bar": bar} + # Default save=false; caller can include save in --data if desired + payload.setdefault("save", False) + + if not settings and "step" not in payload: + print("No settings specified to send.", file=sys.stderr) + return {"settings": {}, "save": False} + + return payload def parse_args() -> argparse.Namespace: - p = argparse.ArgumentParser(description="Send JSON over SPI to ESP32-C3") + p = argparse.ArgumentParser(description="Send JSON over SPI to ESP32-C3 (led-bar format)") src = p.add_mutually_exclusive_group() - src.add_argument("--data", help="Raw JSON string to send") - src.add_argument("--file", help="Path to JSON file to send") + src.add_argument("--data", help="Raw JSON string to send (passthrough)") + src.add_argument("--file", help="Path to JSON file to send (passthrough)") - p.add_argument("--beat", action="store_true", help="Send as beat message (t=b)") - p.add_argument("--brightness", type=int, help="Brightness (br)") - p.add_argument("--delay", type=int, help="Delay (dl)") - p.add_argument("--pattern", help="Pattern name (pt)") + p.add_argument("--brightness", type=int, help="Brightness") + p.add_argument("--delay", type=int, help="Delay (ms)") + p.add_argument("--pattern", help="Pattern name") p.add_argument("--n1", type=int, help="n1 parameter") p.add_argument("--n2", type=int, help="n2 parameter") p.add_argument("--n3", type=int, help="n3 parameter") - p.add_argument("--step", type=int, help="step (s)") - p.add_argument("--name-value", nargs=2, metavar=("NAME", "JSON"), help="Send override under NAME key with JSON object value") + p.add_argument("--step", type=int, help="Pattern step override") + p.add_argument("--name-value", nargs=2, metavar=("NAME", "JSON"), help="Merge JSON into settings (shortcut)") # SPI params p.add_argument("--bus", type=int, default=0, help="SPI bus (default 0)")