aiolibresync 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiolibresync/__init__.py +86 -0
- aiolibresync/client.py +655 -0
- aiolibresync/connection.py +209 -0
- aiolibresync/const.py +185 -0
- aiolibresync/discovery.py +439 -0
- aiolibresync/exceptions.py +22 -0
- aiolibresync/frames.py +204 -0
- aiolibresync/media.py +239 -0
- aiolibresync/py.typed +0 -0
- aiolibresync/state.py +108 -0
- aiolibresync/systemcontrol.py +212 -0
- aiolibresync-0.3.0.dist-info/METADATA +141 -0
- aiolibresync-0.3.0.dist-info/RECORD +15 -0
- aiolibresync-0.3.0.dist-info/WHEEL +4 -0
- aiolibresync-0.3.0.dist-info/licenses/LICENSE +21 -0
aiolibresync/__init__.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Async client for Libre Wireless LibreSync audio devices.
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from aiolibresync import DeviceState, LibreSyncClient
|
|
5
|
+
|
|
6
|
+
async def main() -> None:
|
|
7
|
+
client = LibreSyncClient("192.168.1.50")
|
|
8
|
+
ready = asyncio.Event()
|
|
9
|
+
|
|
10
|
+
def on_state(state: DeviceState) -> None:
|
|
11
|
+
print(state)
|
|
12
|
+
if state.available:
|
|
13
|
+
ready.set()
|
|
14
|
+
|
|
15
|
+
client.subscribe(on_state)
|
|
16
|
+
await client.async_connect()
|
|
17
|
+
await ready.wait()
|
|
18
|
+
await client.async_set_power(True)
|
|
19
|
+
await asyncio.sleep(60)
|
|
20
|
+
await client.async_disconnect()
|
|
21
|
+
|
|
22
|
+
asyncio.run(main())
|
|
23
|
+
|
|
24
|
+
`async_connect()` returns as soon as the two sockets have been *scheduled*, not
|
|
25
|
+
once they are open, so a command issued on the next line raises
|
|
26
|
+
`NotConnectedError`. `state.available` is the readiness signal — it turns true
|
|
27
|
+
when both ports are connected — and waiting on it is what the example's
|
|
28
|
+
`asyncio.Event` is for. It goes false again on any disconnection, so a long-
|
|
29
|
+
running program should treat it as a condition, not a one-off.
|
|
30
|
+
|
|
31
|
+
`DeviceState` reports playback twice, because the hub does. `play_state` is the
|
|
32
|
+
streaming renderer's transport and answers `PLAYING` to a physical input with
|
|
33
|
+
nothing connected to it; `audio_state` is whether sound is coming out, from
|
|
34
|
+
`02 21` byte 8, and is right on all ten sources. **Read `state.playback`**,
|
|
35
|
+
which is the second wherever it is known and the first otherwise.
|
|
36
|
+
|
|
37
|
+
Finding a hub, when its address is not already known:
|
|
38
|
+
|
|
39
|
+
from aiolibresync import async_discover
|
|
40
|
+
|
|
41
|
+
for device in await async_discover():
|
|
42
|
+
print(device.host, device.udn, device.name)
|
|
43
|
+
|
|
44
|
+
`async_discover()` sends a multicast search and waits the full timeout — it does
|
|
45
|
+
not return early on the first answer — and `async_probe(host)` performs the same
|
|
46
|
+
identification for an address the user already has. Both are read-only: a
|
|
47
|
+
search, an HTTP GET of the device description, and a TCP connect to 50006 that
|
|
48
|
+
sends nothing.
|
|
49
|
+
|
|
50
|
+
The codec is importable on its own — `aiolibresync.frames`,
|
|
51
|
+
`aiolibresync.systemcontrol`, `aiolibresync.media` — and does no I/O.
|
|
52
|
+
`frames.build_media` is deliberately not re-exported here: its `command`
|
|
53
|
+
argument is a LUCI message-box id, and the box space includes factory reset.
|
|
54
|
+
Use the named operations in `aiolibresync.media` instead.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
from .client import LibreSyncClient
|
|
58
|
+
from .const import CONTROL_PORT, MEDIA_PORT, POLL_INTERVAL
|
|
59
|
+
from .discovery import DiscoveredDevice, async_discover, async_probe
|
|
60
|
+
from .exceptions import (
|
|
61
|
+
ConfirmationTimeout,
|
|
62
|
+
LibreSyncError,
|
|
63
|
+
NotConnectedError,
|
|
64
|
+
UnsafeCommandError,
|
|
65
|
+
)
|
|
66
|
+
from .state import DeviceState, NowPlaying, PlayState, Source
|
|
67
|
+
|
|
68
|
+
__version__ = "0.2.0"
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
"CONTROL_PORT",
|
|
72
|
+
"MEDIA_PORT",
|
|
73
|
+
"POLL_INTERVAL",
|
|
74
|
+
"ConfirmationTimeout",
|
|
75
|
+
"DeviceState",
|
|
76
|
+
"DiscoveredDevice",
|
|
77
|
+
"LibreSyncClient",
|
|
78
|
+
"LibreSyncError",
|
|
79
|
+
"NotConnectedError",
|
|
80
|
+
"NowPlaying",
|
|
81
|
+
"PlayState",
|
|
82
|
+
"Source",
|
|
83
|
+
"UnsafeCommandError",
|
|
84
|
+
"async_discover",
|
|
85
|
+
"async_probe",
|
|
86
|
+
]
|