Files
home_assistant/wled_push.py
T
tomatocream 3812dbc8ad Add WLED pull/push scripts and config backup
- wled_pull.py: fetch state, info, cfg, effects, palettes from WLED
- wled_push.py: send commands or JSON state to WLED
- wled_config/: saved full.json, state.json, info.json from 192.168.240.30

Made-with: Cursor
2026-03-08 00:52:20 +08:00

92 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""
Push state/commands to a WLED device.
Accepts a JSON file or simple flags (on, off, bri, preset).
Uses only standard library (no pip install).
"""
import argparse
import json
import sys
from typing import Optional
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
DEFAULT_HOST = "192.168.240.30"
def push(host: str, payload: dict, return_state: bool = False) -> Optional[dict]:
base = host if host.startswith("http") else f"http://{host}"
url = f"{base}/json/state"
if return_state:
payload["v"] = True
body = json.dumps(payload).encode("utf-8")
req = Request(
url,
data=body,
method="POST",
headers={"Content-Type": "application/json", "Accept": "application/json"},
)
try:
with urlopen(req, timeout=10) as r:
raw = r.read().decode()
if not raw:
return None
return json.loads(raw)
except HTTPError as e:
print(f"HTTP error: {e.code} {e.reason}", file=sys.stderr)
if e.fp:
print(e.fp.read().decode(), file=sys.stderr)
sys.exit(1)
except URLError as e:
print(f"Request failed: {e.reason}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Invalid response JSON: {e}", file=sys.stderr)
sys.exit(1)
def main():
p = argparse.ArgumentParser(description="Push state/commands to WLED")
p.add_argument("--host", "-H", default=DEFAULT_HOST, help=f"WLED host (default: {DEFAULT_HOST})")
p.add_argument("--file", "-f", metavar="JSON", help="JSON file with state to send")
p.add_argument("--on", action="store_true", help="Turn on")
p.add_argument("--off", action="store_true", help="Turn off")
p.add_argument("--toggle", "-t", action="store_true", dest="toggle", help="Toggle on/off")
p.add_argument("--bri", type=int, metavar="0-255", help="Brightness")
p.add_argument("--preset", "-p", type=int, metavar="ID", help="Load preset by ID")
p.add_argument("--v", action="store_true", help="Return full state in response")
args = p.parse_args()
if args.file:
with open(args.file) as f:
payload = json.load(f)
else:
payload = {}
if args.off:
payload["on"] = False
if args.on:
payload["on"] = True
if args.toggle:
payload["on"] = "t"
if args.bri is not None:
payload["bri"] = max(0, min(255, args.bri))
if args.preset is not None:
payload["ps"] = args.preset
if args.v:
payload["v"] = True
if not payload:
print("Nothing to send. Use --file, --on, --off, --toggle, --bri, or --preset.", file=sys.stderr)
sys.exit(1)
out = push(args.host, payload, return_state=args.v)
if out:
print(json.dumps(out, indent=2))
if __name__ == "__main__":
main()