Skip to content

Commit c8c937a

Browse files
authored
Add ability to reboot device (#321)
1 parent 4941d74 commit c8c937a

3 files changed

Lines changed: 60 additions & 38 deletions

File tree

examples/control.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88

99
async def main():
1010
"""Show example on controlling your WLED device."""
11-
async with WLED("10.10.11.82") as led:
11+
async with WLED("10.10.11.135") as led:
1212
device = await led.update()
1313
print(device.info.version)
1414

1515
# Turn strip on, full brightness
16-
await led.master(on=False, brightness=255)
16+
await led.master(on=True, brightness=255)
1717

1818

1919
if __name__ == "__main__":

src/wled/wled.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ async def request(
137137
the WLED device.
138138
139139
Args:
140-
uri: Request URI, for example `si`.
140+
uri: Request URI, for example `/json/si`.
141141
method: HTTP method to use for the request.E.g., "GET" or "POST".
142142
data: Dictionary of data to send to the WLED device.
143143
@@ -152,9 +152,7 @@ async def request(
152152
with the WLED device.
153153
WLEDError: Received an unexpected response from the WLED device.
154154
"""
155-
url = URL.build(scheme="http", host=self.host, port=80, path="/json/").join(
156-
URL(uri)
157-
)
155+
url = URL.build(scheme="http", host=self.host, port=80, path=uri)
158156

159157
headers = {
160158
"Accept": "application/json, text/plain, */*",
@@ -165,7 +163,7 @@ async def request(
165163
self._close_session = True
166164

167165
# If updating the state, always request for a state response
168-
if method == "POST" and uri == "state" and data is not None:
166+
if method == "POST" and uri == "/json/state" and data is not None:
169167
data["v"] = True
170168

171169
try:
@@ -198,7 +196,7 @@ async def request(
198196
response_data = await response.json()
199197
if (
200198
method == "POST"
201-
and uri == "state"
199+
and uri == "/json/state"
202200
and self._device is not None
203201
and data is not None
204202
):
@@ -226,7 +224,7 @@ async def update(self, full_update: bool = False) -> Device:
226224
WLEDEmptyResponseError: The WLED device returned an empty response.
227225
"""
228226
if self._device is None or full_update:
229-
data = await self.request()
227+
data = await self.request("/json")
230228
if not data:
231229
raise WLEDEmptyResponseError(
232230
f"WLED device at {self.host} returned an empty API"
@@ -244,7 +242,7 @@ async def update(self, full_update: bool = False) -> Device:
244242
except version.InvalidVersion:
245243
# Could be a manual build one? Lets poll for it
246244
try:
247-
await self.request("si")
245+
await self.request("/json/si")
248246
self._supports_si_request = True
249247
except WLEDError:
250248
self._supports_si_request = False
@@ -253,14 +251,14 @@ async def update(self, full_update: bool = False) -> Device:
253251

254252
# Handle legacy state and update in separate requests
255253
if not self._supports_si_request:
256-
info = await self.request("info")
254+
info = await self.request("/json/info")
257255
if not info:
258256
raise WLEDEmptyResponseError(
259257
f"WLED device at {self.host} returned an empty API"
260258
" response on info update"
261259
)
262260

263-
state = await self.request("state")
261+
state = await self.request("/json/state")
264262
if not state:
265263
raise WLEDEmptyResponseError(
266264
f"WLED device {self.host} returned an empty API"
@@ -269,7 +267,7 @@ async def update(self, full_update: bool = False) -> Device:
269267
self._device.update_from_dict({"info": info, "state": state})
270268
return self._device
271269

272-
state_info = await self.request("si")
270+
state_info = await self.request("/json/si")
273271
if not state_info:
274272
raise WLEDEmptyResponseError(
275273
f"WLED device at {self.host} returned an empty API"
@@ -305,7 +303,7 @@ async def master(
305303
if transition is not None:
306304
state["tt"] = transition
307305

308-
await self.request("state", method="POST", data=state)
306+
await self.request("/json/state", method="POST", data=state)
309307

310308
async def segment( # pylint: disable=too-many-locals, too-many-branches
311309
self,
@@ -442,7 +440,7 @@ async def segment( # pylint: disable=too-many-locals, too-many-branches
442440
if transition is not None:
443441
state["tt"] = transition
444442

445-
await self.request("state", method="POST", data=state)
443+
await self.request("/json/state", method="POST", data=state)
446444

447445
async def transition(self, transition: int) -> None:
448446
"""Set the default transition time for manual control.
@@ -452,23 +450,25 @@ async def transition(self, transition: int) -> None:
452450
colors/brightness levels. One unit is 100ms, so a value of 4
453451
results in a transition of 400ms.
454452
"""
455-
await self.request("state", method="POST", data={"transition": transition})
453+
await self.request(
454+
"/json/state", method="POST", data={"transition": transition}
455+
)
456456

457457
async def preset(self, preset: int) -> None:
458458
"""Set a preset on a WLED device.
459459
460460
Args:
461461
preset: The preset number to activate on this WLED device.
462462
"""
463-
await self.request("state", method="POST", data={"ps": preset})
463+
await self.request("/json/state", method="POST", data={"ps": preset})
464464

465465
async def live(self, live: Live) -> None:
466466
"""Set the live override mode on a WLED device.
467467
468468
Args:
469469
live: The live override mode to set on this WLED device.
470470
"""
471-
await self.request("state", method="POST", data={"lor": live.value})
471+
await self.request("/json/state", method="POST", data={"lor": live.value})
472472

473473
async def playlist(self, playlist: int) -> None:
474474
"""Set a running playlist on a WLED device.
@@ -477,7 +477,7 @@ async def playlist(self, playlist: int) -> None:
477477
playlist: ID of playlist to run. For now, this sets the preset
478478
cycle feature, -1 is off and 0 is on.
479479
"""
480-
await self.request("state", method="POST", data={"pl": playlist})
480+
await self.request("/json/state", method="POST", data={"pl": playlist})
481481

482482
async def sync(
483483
self, *, send: bool | None = None, receive: bool | None = None
@@ -490,7 +490,7 @@ async def sync(
490490
"""
491491
sync = {"send": send, "recv": receive}
492492
sync = {k: v for k, v in sync.items() if v is not None}
493-
await self.request("state", method="POST", data={"udpn": sync})
493+
await self.request("/json/state", method="POST", data={"udpn": sync})
494494

495495
async def nightlight(
496496
self,
@@ -524,7 +524,11 @@ async def nightlight(
524524
if on:
525525
state["on"] = True
526526

527-
await self.request("state", method="POST", data=state)
527+
await self.request("/json/state", method="POST", data=state)
528+
529+
async def reset(self) -> None:
530+
"""Reboot WLED device."""
531+
await self.request("/reset")
528532

529533
async def close(self) -> None:
530534
"""Close open client (WebSocket) session."""
@@ -546,5 +550,4 @@ async def __aexit__(self, *_exc_info) -> None:
546550
Args:
547551
_exc_info: Exec type.
548552
"""
549-
print("Disconnecting nicely....")
550553
await self.close()

tests/test_wled.py

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ async def test_state_on(aresponses):
151151
"""Test request of current WLED device state."""
152152
aresponses.add(
153153
"example.com",
154-
"/json/",
154+
"/json",
155155
"GET",
156156
aresponses.Response(
157157
status=200,
@@ -196,7 +196,7 @@ async def test_state_on_si_request(aresponses):
196196
"""Test request of current WLED device state."""
197197
aresponses.add(
198198
"example.com",
199-
"/json/",
199+
"/json",
200200
"GET",
201201
aresponses.Response(
202202
status=200,
@@ -231,7 +231,7 @@ async def test_empty_responses(aresponses):
231231
"""Test empty responses for WLED device state."""
232232
aresponses.add(
233233
"example.com",
234-
"/json/",
234+
"/json",
235235
"GET",
236236
aresponses.Response(
237237
status=200,
@@ -304,7 +304,7 @@ async def test_empty_si_responses(aresponses):
304304
"""Test request of current WLED device state."""
305305
aresponses.add(
306306
"example.com",
307-
"/json/",
307+
"/json",
308308
"GET",
309309
aresponses.Response(
310310
status=200,
@@ -347,7 +347,7 @@ async def test_empty_full_responses(aresponses):
347347
"""Test failure handling of full data request WLED device state."""
348348
aresponses.add(
349349
"example.com",
350-
"/json/",
350+
"/json",
351351
"GET",
352352
aresponses.Response(
353353
status=200,
@@ -357,7 +357,7 @@ async def test_empty_full_responses(aresponses):
357357
)
358358
aresponses.add(
359359
"example.com",
360-
"/json/",
360+
"/json",
361361
"GET",
362362
aresponses.Response(
363363
status=200,
@@ -379,7 +379,7 @@ async def test_si_request_version_based(aresponses):
379379
"""Test for supporting SI requests based on version data."""
380380
aresponses.add(
381381
"example.com",
382-
"/json/",
382+
"/json",
383383
"GET",
384384
aresponses.Response(
385385
status=200,
@@ -403,7 +403,7 @@ async def test_not_supporting_si_request_version_based(aresponses):
403403
"""Test for supporting SI requests based on version data."""
404404
aresponses.add(
405405
"example.com",
406-
"/json/",
406+
"/json",
407407
"GET",
408408
aresponses.Response(
409409
status=200,
@@ -427,7 +427,7 @@ async def test_si_request_probing_based(aresponses):
427427
"""Test for supporting SI requests based on probing."""
428428
aresponses.add(
429429
"example.com",
430-
"/json/",
430+
"/json",
431431
"GET",
432432
aresponses.Response(
433433
status=200,
@@ -462,7 +462,7 @@ async def test_not_supporting_si_request_probing_based(aresponses):
462462
"""Test for supporting SI requests based on probing."""
463463
aresponses.add(
464464
"example.com",
465-
"/json/",
465+
"/json",
466466
"GET",
467467
aresponses.Response(
468468
status=200,
@@ -486,7 +486,7 @@ async def test_info_contains_wv_true(aresponses):
486486
"""Test for determining if wv is used and set to true."""
487487
aresponses.add(
488488
"example.com",
489-
"/json/",
489+
"/json",
490490
"GET",
491491
aresponses.Response(
492492
status=200,
@@ -516,7 +516,7 @@ async def test_info_contains_wv_false(aresponses):
516516
"""Test for determining if wv is used and set to false."""
517517
aresponses.add(
518518
"example.com",
519-
"/json/",
519+
"/json",
520520
"GET",
521521
aresponses.Response(
522522
status=200,
@@ -546,7 +546,7 @@ async def test_info_contains_no_wv(aresponses):
546546
"""Test for determining if wv is used and set to false."""
547547
aresponses.add(
548548
"example.com",
549-
"/json/",
549+
"/json",
550550
"GET",
551551
aresponses.Response(
552552
status=200,
@@ -575,7 +575,7 @@ async def test_live_override_state_off(aresponses):
575575
"""Test request of current WLED live override mode."""
576576
aresponses.add(
577577
"example.com",
578-
"/json/",
578+
"/json",
579579
"GET",
580580
aresponses.Response(
581581
status=200,
@@ -599,7 +599,7 @@ async def test_live_override_state_on(aresponses):
599599
"""Test request of current WLED live override mode."""
600600
aresponses.add(
601601
"example.com",
602-
"/json/",
602+
"/json",
603603
"GET",
604604
aresponses.Response(
605605
status=200,
@@ -623,7 +623,7 @@ async def test_live_override_state_off_until_reboot(aresponses):
623623
"""Test request of current WLED live override mode."""
624624
aresponses.add(
625625
"example.com",
626-
"/json/",
626+
"/json",
627627
"GET",
628628
aresponses.Response(
629629
status=200,
@@ -640,3 +640,22 @@ async def test_live_override_state_off_until_reboot(aresponses):
640640
wled = WLED("example.com", session=session)
641641
device = await wled.update()
642642
assert device.state.lor == 2
643+
644+
645+
@pytest.mark.asyncio
646+
async def test_reset(aresponses):
647+
"""Test rebooting WLED device works."""
648+
aresponses.add(
649+
"example.com",
650+
"/reset",
651+
"GET",
652+
aresponses.Response(
653+
status=200,
654+
headers={"Content-Type": "text/html"},
655+
text="<!DOCTYPE html>",
656+
),
657+
)
658+
659+
async with aiohttp.ClientSession() as session:
660+
wled = WLED("example.com", session=session)
661+
await wled.reset()

0 commit comments

Comments
 (0)