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
This commit is contained in:
@@ -0,0 +1,427 @@
|
|||||||
|
{
|
||||||
|
"state": {
|
||||||
|
"on": true,
|
||||||
|
"bri": 254,
|
||||||
|
"transition": 7,
|
||||||
|
"ps": -1,
|
||||||
|
"pl": -1,
|
||||||
|
"ledmap": 0,
|
||||||
|
"AudioReactive": {
|
||||||
|
"on": true
|
||||||
|
},
|
||||||
|
"nl": {
|
||||||
|
"on": false,
|
||||||
|
"dur": 60,
|
||||||
|
"mode": 1,
|
||||||
|
"tbri": 0,
|
||||||
|
"rem": -1
|
||||||
|
},
|
||||||
|
"udpn": {
|
||||||
|
"send": false,
|
||||||
|
"recv": true,
|
||||||
|
"sgrp": 1,
|
||||||
|
"rgrp": 1
|
||||||
|
},
|
||||||
|
"lor": 0,
|
||||||
|
"mainseg": 0,
|
||||||
|
"seg": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"start": 0,
|
||||||
|
"stop": 1,
|
||||||
|
"len": 1,
|
||||||
|
"grp": 1,
|
||||||
|
"spc": 0,
|
||||||
|
"of": 0,
|
||||||
|
"on": true,
|
||||||
|
"frz": false,
|
||||||
|
"bri": 255,
|
||||||
|
"cct": 0,
|
||||||
|
"set": 0,
|
||||||
|
"col": [
|
||||||
|
[
|
||||||
|
56,
|
||||||
|
56,
|
||||||
|
56,
|
||||||
|
56
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"fx": 0,
|
||||||
|
"sx": 128,
|
||||||
|
"ix": 128,
|
||||||
|
"pal": 0,
|
||||||
|
"c1": 128,
|
||||||
|
"c2": 128,
|
||||||
|
"c3": 16,
|
||||||
|
"sel": true,
|
||||||
|
"rev": false,
|
||||||
|
"mi": false,
|
||||||
|
"o1": false,
|
||||||
|
"o2": false,
|
||||||
|
"o3": false,
|
||||||
|
"si": 0,
|
||||||
|
"m12": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"ver": "0.15.1",
|
||||||
|
"vid": 2507300,
|
||||||
|
"cn": "K\u014dsen",
|
||||||
|
"release": "ESP32",
|
||||||
|
"leds": {
|
||||||
|
"count": 1,
|
||||||
|
"pwr": 120,
|
||||||
|
"fps": 2,
|
||||||
|
"maxpwr": 20000,
|
||||||
|
"maxseg": 32,
|
||||||
|
"bootps": 0,
|
||||||
|
"seglc": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"lc": 6,
|
||||||
|
"rgbw": false,
|
||||||
|
"wv": 2,
|
||||||
|
"cct": 4
|
||||||
|
},
|
||||||
|
"str": false,
|
||||||
|
"name": "WLED-Gledopto",
|
||||||
|
"udpport": 21324,
|
||||||
|
"simplifiedui": false,
|
||||||
|
"live": false,
|
||||||
|
"liveseg": -1,
|
||||||
|
"lm": "",
|
||||||
|
"lip": "",
|
||||||
|
"ws": 1,
|
||||||
|
"fxcount": 187,
|
||||||
|
"palcount": 71,
|
||||||
|
"cpalcount": 0,
|
||||||
|
"maps": [
|
||||||
|
{
|
||||||
|
"id": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"wifi": {
|
||||||
|
"bssid": "A4:A9:30:F9:4D:96",
|
||||||
|
"rssi": -49,
|
||||||
|
"signal": 100,
|
||||||
|
"channel": 1,
|
||||||
|
"ap": false
|
||||||
|
},
|
||||||
|
"fs": {
|
||||||
|
"u": 8,
|
||||||
|
"t": 983,
|
||||||
|
"pmt": 1772891797
|
||||||
|
},
|
||||||
|
"ndc": 0,
|
||||||
|
"arch": "esp32",
|
||||||
|
"core": "v3.3.6-16-gcc5440f6a2",
|
||||||
|
"clock": 240,
|
||||||
|
"flash": 4,
|
||||||
|
"lwip": 0,
|
||||||
|
"freeheap": 169496,
|
||||||
|
"uptime": 10830,
|
||||||
|
"time": "2026-3-7, 16:52:59",
|
||||||
|
"u": {
|
||||||
|
"AudioReactive": [
|
||||||
|
"<button class=\"btn btn-xs\" onclick=\"requestJson({AudioReactive:{enabled:false}});\"><i class=\"icons on\"></i></button>"
|
||||||
|
],
|
||||||
|
"GEQ Input Level": [
|
||||||
|
"<div class=\"slider\"><div class=\"sliderwrap il\"><input class=\"noslide\" onchange=\"requestJson({AudioReactive:{inputLevel:parseInt(this.value)}});\" oninput=\"updateTrail(this);\" max=255 min=0 type=\"range\" value=128 /><div class=\"sliderdisplay\"></div></div></div>"
|
||||||
|
],
|
||||||
|
"Audio Source": [
|
||||||
|
"I2S digital",
|
||||||
|
" - peak 99%"
|
||||||
|
],
|
||||||
|
"Sound Processing": [
|
||||||
|
"running"
|
||||||
|
],
|
||||||
|
"AGC Gain": [
|
||||||
|
8.46,
|
||||||
|
"x"
|
||||||
|
],
|
||||||
|
"UDP Sound Sync": [
|
||||||
|
"off"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"opt": 79,
|
||||||
|
"brand": "WLED",
|
||||||
|
"product": "FOSS",
|
||||||
|
"mac": "b0cbd8e1a8c8",
|
||||||
|
"ip": "192.168.240.30"
|
||||||
|
},
|
||||||
|
"effects": [
|
||||||
|
"Solid",
|
||||||
|
"Blink",
|
||||||
|
"Breathe",
|
||||||
|
"Wipe",
|
||||||
|
"Wipe Random",
|
||||||
|
"Random Colors",
|
||||||
|
"Sweep",
|
||||||
|
"Dynamic",
|
||||||
|
"Colorloop",
|
||||||
|
"Rainbow",
|
||||||
|
"Scan",
|
||||||
|
"Scan Dual",
|
||||||
|
"Fade",
|
||||||
|
"Theater",
|
||||||
|
"Theater Rainbow",
|
||||||
|
"Running",
|
||||||
|
"Saw",
|
||||||
|
"Twinkle",
|
||||||
|
"Dissolve",
|
||||||
|
"Dissolve Rnd",
|
||||||
|
"Sparkle",
|
||||||
|
"Sparkle Dark",
|
||||||
|
"Sparkle+",
|
||||||
|
"Strobe",
|
||||||
|
"Strobe Rainbow",
|
||||||
|
"Strobe Mega",
|
||||||
|
"Blink Rainbow",
|
||||||
|
"Android",
|
||||||
|
"Chase",
|
||||||
|
"Chase Random",
|
||||||
|
"Chase Rainbow",
|
||||||
|
"Chase Flash",
|
||||||
|
"Chase Flash Rnd",
|
||||||
|
"Rainbow Runner",
|
||||||
|
"Colorful",
|
||||||
|
"Traffic Light",
|
||||||
|
"Sweep Random",
|
||||||
|
"Chase 2",
|
||||||
|
"Aurora",
|
||||||
|
"Stream",
|
||||||
|
"Scanner",
|
||||||
|
"Lighthouse",
|
||||||
|
"Fireworks",
|
||||||
|
"Rain",
|
||||||
|
"Tetrix",
|
||||||
|
"Fire Flicker",
|
||||||
|
"Gradient",
|
||||||
|
"Loading",
|
||||||
|
"Rolling Balls",
|
||||||
|
"Fairy",
|
||||||
|
"Two Dots",
|
||||||
|
"Fairytwinkle",
|
||||||
|
"Running Dual",
|
||||||
|
"RSVD",
|
||||||
|
"Chase 3",
|
||||||
|
"Tri Wipe",
|
||||||
|
"Tri Fade",
|
||||||
|
"Lightning",
|
||||||
|
"ICU",
|
||||||
|
"Multi Comet",
|
||||||
|
"Scanner Dual",
|
||||||
|
"Stream 2",
|
||||||
|
"Oscillate",
|
||||||
|
"Pride 2015",
|
||||||
|
"Juggle",
|
||||||
|
"Palette",
|
||||||
|
"Fire 2012",
|
||||||
|
"Colorwaves",
|
||||||
|
"Bpm",
|
||||||
|
"Fill Noise",
|
||||||
|
"Noise 1",
|
||||||
|
"Noise 2",
|
||||||
|
"Noise 3",
|
||||||
|
"Noise 4",
|
||||||
|
"Colortwinkles",
|
||||||
|
"Lake",
|
||||||
|
"Meteor",
|
||||||
|
"Meteor Smooth",
|
||||||
|
"Railway",
|
||||||
|
"Ripple",
|
||||||
|
"Twinklefox",
|
||||||
|
"Twinklecat",
|
||||||
|
"Halloween Eyes",
|
||||||
|
"Solid Pattern",
|
||||||
|
"Solid Pattern Tri",
|
||||||
|
"Spots",
|
||||||
|
"Spots Fade",
|
||||||
|
"Glitter",
|
||||||
|
"Candle",
|
||||||
|
"Fireworks Starburst",
|
||||||
|
"Fireworks 1D",
|
||||||
|
"Bouncing Balls",
|
||||||
|
"Sinelon",
|
||||||
|
"Sinelon Dual",
|
||||||
|
"Sinelon Rainbow",
|
||||||
|
"Popcorn",
|
||||||
|
"Drip",
|
||||||
|
"Plasma",
|
||||||
|
"Percent",
|
||||||
|
"Ripple Rainbow",
|
||||||
|
"Heartbeat",
|
||||||
|
"Pacifica",
|
||||||
|
"Candle Multi",
|
||||||
|
"Solid Glitter",
|
||||||
|
"Sunrise",
|
||||||
|
"Phased",
|
||||||
|
"Twinkleup",
|
||||||
|
"Noise Pal",
|
||||||
|
"Sine",
|
||||||
|
"Phased Noise",
|
||||||
|
"Flow",
|
||||||
|
"Chunchun",
|
||||||
|
"Dancing Shadows",
|
||||||
|
"Washing Machine",
|
||||||
|
"Rotozoomer",
|
||||||
|
"Blends",
|
||||||
|
"TV Simulator",
|
||||||
|
"Dynamic Smooth",
|
||||||
|
"Spaceships",
|
||||||
|
"Crazy Bees",
|
||||||
|
"Ghost Rider",
|
||||||
|
"Blobs",
|
||||||
|
"Scrolling Text",
|
||||||
|
"Drift Rose",
|
||||||
|
"Distortion Waves",
|
||||||
|
"Soap",
|
||||||
|
"Octopus",
|
||||||
|
"Waving Cell",
|
||||||
|
"Pixels",
|
||||||
|
"Pixelwave",
|
||||||
|
"Juggles",
|
||||||
|
"Matripix",
|
||||||
|
"Gravimeter",
|
||||||
|
"Plasmoid",
|
||||||
|
"Puddles",
|
||||||
|
"Midnoise",
|
||||||
|
"Noisemeter",
|
||||||
|
"Freqwave",
|
||||||
|
"Freqmatrix",
|
||||||
|
"GEQ",
|
||||||
|
"Waterfall",
|
||||||
|
"Freqpixels",
|
||||||
|
"RSVD",
|
||||||
|
"Noisefire",
|
||||||
|
"Puddlepeak",
|
||||||
|
"Noisemove",
|
||||||
|
"Noise2D",
|
||||||
|
"Perlin Move",
|
||||||
|
"Ripple Peak",
|
||||||
|
"Firenoise",
|
||||||
|
"Squared Swirl",
|
||||||
|
"RSVD",
|
||||||
|
"DNA",
|
||||||
|
"Matrix",
|
||||||
|
"Metaballs",
|
||||||
|
"Freqmap",
|
||||||
|
"Gravcenter",
|
||||||
|
"Gravcentric",
|
||||||
|
"Gravfreq",
|
||||||
|
"DJ Light",
|
||||||
|
"Funky Plank",
|
||||||
|
"RSVD",
|
||||||
|
"Pulser",
|
||||||
|
"Blurz",
|
||||||
|
"Drift",
|
||||||
|
"Waverly",
|
||||||
|
"Sun Radiation",
|
||||||
|
"Colored Bursts",
|
||||||
|
"Julia",
|
||||||
|
"RSVD",
|
||||||
|
"RSVD",
|
||||||
|
"RSVD",
|
||||||
|
"Game Of Life",
|
||||||
|
"Tartan",
|
||||||
|
"Polar Lights",
|
||||||
|
"Swirl",
|
||||||
|
"Lissajous",
|
||||||
|
"Frizzles",
|
||||||
|
"Plasma Ball",
|
||||||
|
"Flow Stripe",
|
||||||
|
"Hiphotic",
|
||||||
|
"Sindots",
|
||||||
|
"DNA Spiral",
|
||||||
|
"Black Hole",
|
||||||
|
"Wavesins",
|
||||||
|
"Rocktaves",
|
||||||
|
"Akemi"
|
||||||
|
],
|
||||||
|
"palettes": [
|
||||||
|
"Default",
|
||||||
|
"* Random Cycle",
|
||||||
|
"* Color 1",
|
||||||
|
"* Colors 1&2",
|
||||||
|
"* Color Gradient",
|
||||||
|
"* Colors Only",
|
||||||
|
"Party",
|
||||||
|
"Cloud",
|
||||||
|
"Lava",
|
||||||
|
"Ocean",
|
||||||
|
"Forest",
|
||||||
|
"Rainbow",
|
||||||
|
"Rainbow Bands",
|
||||||
|
"Sunset",
|
||||||
|
"Rivendell",
|
||||||
|
"Breeze",
|
||||||
|
"Red & Blue",
|
||||||
|
"Yellowout",
|
||||||
|
"Analogous",
|
||||||
|
"Splash",
|
||||||
|
"Pastel",
|
||||||
|
"Sunset 2",
|
||||||
|
"Beach",
|
||||||
|
"Vintage",
|
||||||
|
"Departure",
|
||||||
|
"Landscape",
|
||||||
|
"Beech",
|
||||||
|
"Sherbet",
|
||||||
|
"Hult",
|
||||||
|
"Hult 64",
|
||||||
|
"Drywet",
|
||||||
|
"Jul",
|
||||||
|
"Grintage",
|
||||||
|
"Rewhi",
|
||||||
|
"Tertiary",
|
||||||
|
"Fire",
|
||||||
|
"Icefire",
|
||||||
|
"Cyane",
|
||||||
|
"Light Pink",
|
||||||
|
"Autumn",
|
||||||
|
"Magenta",
|
||||||
|
"Magred",
|
||||||
|
"Yelmag",
|
||||||
|
"Yelblu",
|
||||||
|
"Orange & Teal",
|
||||||
|
"Tiamat",
|
||||||
|
"April Night",
|
||||||
|
"Orangery",
|
||||||
|
"C9",
|
||||||
|
"Sakura",
|
||||||
|
"Aurora",
|
||||||
|
"Atlantica",
|
||||||
|
"C9 2",
|
||||||
|
"C9 New",
|
||||||
|
"Temperature",
|
||||||
|
"Aurora 2",
|
||||||
|
"Retro Clown",
|
||||||
|
"Candy",
|
||||||
|
"Toxy Reaf",
|
||||||
|
"Fairy Reaf",
|
||||||
|
"Semi Blue",
|
||||||
|
"Pink Candy",
|
||||||
|
"Red Reaf",
|
||||||
|
"Aqua Flash",
|
||||||
|
"Yelblu Hot",
|
||||||
|
"Lite Light",
|
||||||
|
"Red Flash",
|
||||||
|
"Blink Red",
|
||||||
|
"Red Shift",
|
||||||
|
"Red Tide",
|
||||||
|
"Candy2"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"ver": "0.15.1",
|
||||||
|
"vid": 2507300,
|
||||||
|
"cn": "K\u014dsen",
|
||||||
|
"release": "ESP32",
|
||||||
|
"leds": {
|
||||||
|
"count": 1,
|
||||||
|
"pwr": 120,
|
||||||
|
"fps": 2,
|
||||||
|
"maxpwr": 20000,
|
||||||
|
"maxseg": 32,
|
||||||
|
"bootps": 0,
|
||||||
|
"seglc": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"lc": 6,
|
||||||
|
"rgbw": false,
|
||||||
|
"wv": 2,
|
||||||
|
"cct": 4
|
||||||
|
},
|
||||||
|
"str": false,
|
||||||
|
"name": "WLED-Gledopto",
|
||||||
|
"udpport": 21324,
|
||||||
|
"simplifiedui": false,
|
||||||
|
"live": false,
|
||||||
|
"liveseg": -1,
|
||||||
|
"lm": "",
|
||||||
|
"lip": "",
|
||||||
|
"ws": 1,
|
||||||
|
"fxcount": 187,
|
||||||
|
"palcount": 71,
|
||||||
|
"cpalcount": 0,
|
||||||
|
"maps": [
|
||||||
|
{
|
||||||
|
"id": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"wifi": {
|
||||||
|
"bssid": "A4:A9:30:F9:4D:96",
|
||||||
|
"rssi": -50,
|
||||||
|
"signal": 100,
|
||||||
|
"channel": 1,
|
||||||
|
"ap": false
|
||||||
|
},
|
||||||
|
"fs": {
|
||||||
|
"u": 8,
|
||||||
|
"t": 983,
|
||||||
|
"pmt": 1772891797
|
||||||
|
},
|
||||||
|
"ndc": 0,
|
||||||
|
"arch": "esp32",
|
||||||
|
"core": "v3.3.6-16-gcc5440f6a2",
|
||||||
|
"clock": 240,
|
||||||
|
"flash": 4,
|
||||||
|
"lwip": 0,
|
||||||
|
"freeheap": 169488,
|
||||||
|
"uptime": 10831,
|
||||||
|
"time": "2026-3-7, 16:53:00",
|
||||||
|
"u": {
|
||||||
|
"AudioReactive": [
|
||||||
|
"<button class=\"btn btn-xs\" onclick=\"requestJson({AudioReactive:{enabled:false}});\"><i class=\"icons on\"></i></button>"
|
||||||
|
],
|
||||||
|
"GEQ Input Level": [
|
||||||
|
"<div class=\"slider\"><div class=\"sliderwrap il\"><input class=\"noslide\" onchange=\"requestJson({AudioReactive:{inputLevel:parseInt(this.value)}});\" oninput=\"updateTrail(this);\" max=255 min=0 type=\"range\" value=128 /><div class=\"sliderdisplay\"></div></div></div>"
|
||||||
|
],
|
||||||
|
"Audio Source": [
|
||||||
|
"I2S digital",
|
||||||
|
" - peak 99%"
|
||||||
|
],
|
||||||
|
"Sound Processing": [
|
||||||
|
"running"
|
||||||
|
],
|
||||||
|
"AGC Gain": [
|
||||||
|
8.46,
|
||||||
|
"x"
|
||||||
|
],
|
||||||
|
"UDP Sound Sync": [
|
||||||
|
"off"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"opt": 79,
|
||||||
|
"brand": "WLED",
|
||||||
|
"product": "FOSS",
|
||||||
|
"mac": "b0cbd8e1a8c8",
|
||||||
|
"ip": "192.168.240.30"
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"on": true,
|
||||||
|
"bri": 254,
|
||||||
|
"transition": 7,
|
||||||
|
"ps": -1,
|
||||||
|
"pl": -1,
|
||||||
|
"ledmap": 0,
|
||||||
|
"AudioReactive": {
|
||||||
|
"on": true
|
||||||
|
},
|
||||||
|
"nl": {
|
||||||
|
"on": false,
|
||||||
|
"dur": 60,
|
||||||
|
"mode": 1,
|
||||||
|
"tbri": 0,
|
||||||
|
"rem": -1
|
||||||
|
},
|
||||||
|
"udpn": {
|
||||||
|
"send": false,
|
||||||
|
"recv": true,
|
||||||
|
"sgrp": 1,
|
||||||
|
"rgrp": 1
|
||||||
|
},
|
||||||
|
"lor": 0,
|
||||||
|
"mainseg": 0,
|
||||||
|
"seg": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"start": 0,
|
||||||
|
"stop": 1,
|
||||||
|
"len": 1,
|
||||||
|
"grp": 1,
|
||||||
|
"spc": 0,
|
||||||
|
"of": 0,
|
||||||
|
"on": true,
|
||||||
|
"frz": false,
|
||||||
|
"bri": 255,
|
||||||
|
"cct": 0,
|
||||||
|
"set": 0,
|
||||||
|
"col": [
|
||||||
|
[
|
||||||
|
56,
|
||||||
|
56,
|
||||||
|
56,
|
||||||
|
56
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"fx": 0,
|
||||||
|
"sx": 128,
|
||||||
|
"ix": 128,
|
||||||
|
"pal": 0,
|
||||||
|
"c1": 128,
|
||||||
|
"c2": 128,
|
||||||
|
"c3": 16,
|
||||||
|
"sel": true,
|
||||||
|
"rev": false,
|
||||||
|
"mi": false,
|
||||||
|
"o1": false,
|
||||||
|
"o2": false,
|
||||||
|
"o3": false,
|
||||||
|
"si": 0,
|
||||||
|
"m12": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Pull state, config, or info from a WLED device.
|
||||||
|
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"
|
||||||
|
ENDPOINTS = ("state", "info", "cfg", "eff", "pal", "full")
|
||||||
|
|
||||||
|
|
||||||
|
def pull(host: str, endpoint: str, save_path: Optional[str], indent: Optional[int]) -> dict:
|
||||||
|
base = host if host.startswith("http") else f"http://{host}"
|
||||||
|
url = f"{base}/json" if endpoint == "full" else f"{base}/json/{endpoint}"
|
||||||
|
|
||||||
|
req = Request(url, headers={"Accept": "application/json"})
|
||||||
|
try:
|
||||||
|
with urlopen(req, timeout=10) as r:
|
||||||
|
data = json.loads(r.read().decode())
|
||||||
|
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 JSON: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if save_path:
|
||||||
|
with open(save_path, "w") as f:
|
||||||
|
json.dump(data, f, indent=indent or 2)
|
||||||
|
print(f"Saved to {save_path}")
|
||||||
|
else:
|
||||||
|
print(json.dumps(data, indent=indent or 2))
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
p = argparse.ArgumentParser(description="Pull state/config from WLED")
|
||||||
|
p.add_argument("--host", "-H", default=DEFAULT_HOST, help=f"WLED host (default: {DEFAULT_HOST})")
|
||||||
|
p.add_argument(
|
||||||
|
"endpoint",
|
||||||
|
nargs="?",
|
||||||
|
default="full",
|
||||||
|
choices=ENDPOINTS,
|
||||||
|
help="state, info, cfg, eff, pal, or full (default: full)",
|
||||||
|
)
|
||||||
|
p.add_argument("--save", "-o", metavar="FILE", help="Write JSON to file")
|
||||||
|
p.add_argument("--no-indent", action="store_true", help="Compact JSON output")
|
||||||
|
args = p.parse_args()
|
||||||
|
|
||||||
|
pull(
|
||||||
|
args.host,
|
||||||
|
args.endpoint,
|
||||||
|
args.save,
|
||||||
|
None if args.no_indent else 2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/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()
|
||||||
Reference in New Issue
Block a user