vsslctrl 0.1.11.dev1__tar.gz → 0.1.13.dev1__tar.gz

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.
Files changed (33) hide show
  1. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/PKG-INFO +126 -90
  2. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/README.md +124 -88
  3. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/pyproject.toml +1 -1
  4. vsslctrl-0.1.13.dev1/tests/test_event_bus.py +206 -0
  5. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/tests/test_integration.py +319 -253
  6. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/tests/test_settings.py +3 -2
  7. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/tests/test_zone.py +3 -3
  8. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/__init__.py +1 -1
  9. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/api_alpha.py +33 -29
  10. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/api_base.py +25 -0
  11. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/api_bravo.py +6 -0
  12. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/core.py +98 -107
  13. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/data_structure.py +2 -1
  14. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/event_bus.py +23 -26
  15. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/group.py +1 -2
  16. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/track.py +3 -4
  17. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/transport.py +1 -1
  18. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/utils.py +11 -0
  19. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/zone.py +28 -13
  20. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl.egg-info/PKG-INFO +126 -90
  21. vsslctrl-0.1.11.dev1/tests/test_event_bus.py +0 -70
  22. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/LICENSE +0 -0
  23. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/setup.cfg +0 -0
  24. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/decorators.py +0 -0
  25. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/device.py +0 -0
  26. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/discovery.py +0 -0
  27. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/exceptions.py +0 -0
  28. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/io.py +0 -0
  29. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl/settings.py +0 -0
  30. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl.egg-info/SOURCES.txt +0 -0
  31. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl.egg-info/dependency_links.txt +0 -0
  32. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl.egg-info/requires.txt +0 -0
  33. {vsslctrl-0.1.11.dev1 → vsslctrl-0.1.13.dev1}/vsslctrl.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: vsslctrl
3
- Version: 0.1.11.dev1
3
+ Version: 0.1.13.dev1
4
4
  Summary: Package for controlling VSSL's range of streaming amplifiers
5
5
  Author-email: vsslctrl <vsslcontrolled@proton.me>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -21,32 +21,44 @@ Requires-Dist: zeroconf==0.132.2; extra == "optional"
21
21
 
22
22
  # vsslctrl
23
23
 
24
- Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
24
+ Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
25
25
 
26
- **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
26
+ ## Coverage
27
27
 
28
- ## Help
28
+ Tested on:
29
29
 
30
- I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
30
+ | Model | Software Version | Note |
31
+ | ------------|--------- | -------------
32
+ | A.3x | p15305.016.3701 |
31
33
 
32
- Tested on:
33
- - **A.3x** software version **p15305.016.3701**
34
34
 
35
35
  Home Assistant [integration](https://github.com/vsslctrl/integration.home-assistant) with basic functionality working on:
36
- - **A.1** software version **p15265.033.3703** (reported)
37
- - **A.3** software version **p12013.141.3703** (reported)
38
- - **A.3x** software version **p15305.016.3701**
39
- - **A.6x** software version **p15305.017.3701** (reported)
36
+
37
+ | Model | Software Version | User Reported |
38
+ | ------------|--------- | -------------
39
+ | A.1 | p15265.033.3703 | ✔️
40
+ | A.3 | p12013.141.3703 | ✔️
41
+ | A.3x | p15305.016.3701 |
42
+ | A.6x | p15305.017.3701 | ✔️
43
+
44
+
45
+ ## Testers Needed
46
+
47
+ I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
48
+
49
+
40
50
 
41
51
  ## Important
42
52
 
43
- There should not be any *[VSSL Agent's](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* running on the same network. If you dont know what this is, then you can ignore this notice.
53
+ There should not be any *[VSSL Agent's](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* running on the network. If you dont know what this is, then you can ignore this notice.
54
+
55
+ **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
44
56
 
45
57
  ## TODOs
46
58
 
47
- * Correct IO mapping between models and versions
48
59
  * Better test coverage
49
- * A.1(x) testing
60
+ * A.1(x) testing - e.g output settings
61
+ * More controls - e.g IR Control
50
62
 
51
63
  ## Basic Usage
52
64
 
@@ -62,9 +74,9 @@ async def main():
62
74
 
63
75
  # Represents a physical VSSL amplifier
64
76
  vssl = Vssl(DeviceModels.A1)
65
- a1 = vssl.add_zone(ZoneIDs.A1, '192.168.1.10')
77
+ a1 = vssl.add_zone('192.168.1.10')
66
78
 
67
- # Connect and initiate zones.
79
+ # Connect and initialise zone.
68
80
  await vssl.initialise()
69
81
 
70
82
  """Control Examples"""
@@ -92,16 +104,15 @@ from vsslctrl import Vssl, DeviceModels, Zone, ZoneIDs
92
104
  async def main():
93
105
 
94
106
  # Represents a physical VSSL amplifier
95
- # If no DeviceModels is passed, vsslctrl will default to the feature set of the X series amps
96
107
  vssl = Vssl(DeviceModels.A3X)
97
108
 
98
109
  # Add each you wish to control
99
- zone1 = vssl.add_zone(ZoneIDs.ZONE_1, '192.168.1.10')
100
- zone2 = vssl.add_zone(ZoneIDs.ZONE_2, '192.168.1.11')
101
- zone3 = vssl.add_zone(ZoneIDs.ZONE_3, '192.168.1.12')
102
- #... up to 6 zones
110
+ zone1 = vssl.add_zone('192.168.1.10', ZoneIDs.ZONE_1)
111
+ zone2 = vssl.add_zone('192.168.1.11', ZoneIDs.ZONE_2)
112
+ zone3 = vssl.add_zone('192.168.1.12', ZoneIDs.ZONE_3)
113
+ #... up to 6 zones for A.6(x)
103
114
 
104
- # Connect and initiate zones.
115
+ # Connect and initialise zones.
105
116
  await vssl.initialise()
106
117
 
107
118
  """Control Examples"""
@@ -123,24 +134,106 @@ async def main():
123
134
  asyncio.run(main())
124
135
  ```
125
136
 
126
- # API
137
+ ### Device Discovery Helper
138
+
139
+ You can discover VSSL devices on the network using [mDNS](https://wikipedia.org/wiki/Multicast_DNS) / Bonjour if you have the [`zeroconf`](https://pypi.org/project/zeroconf/) package installed.
140
+
141
+ This uses airplay service string `_airplay._tcp.local.`, therefore airplay needs to available and will not work across VLANs without other provisions.
127
142
 
128
- Most functionality is achived via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
143
+ **Note:** This is designed to be a helper and its not recommended to be used for the initialization of the VSSL class.
144
+
145
+ ```python
146
+ import asyncio
147
+ from vsslctrl import Vssl
148
+
149
+ async def main():
150
+
151
+ print(await Vssl.discover())
152
+
153
+ """
154
+ {
155
+ 'XXXXXXXXXXXX': [
156
+ {
157
+ 'host': '192.168.168.25',
158
+ 'name': 'Living Room',
159
+ 'model': 'A1x',
160
+ 'mac_addr': 'AA:BB:CC:DD:EE:FF',
161
+ 'zone_id': '7',
162
+ 'serial': 'XXXXXXXXXXXX'
163
+ }
164
+ ]
165
+ }
166
+
167
+ """
168
+
169
+ asyncio.run(main())
170
+ ```
171
+
172
+
173
+ # API Functionality
174
+
175
+ Most functionality is achieved via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
129
176
 
130
177
  The classes will update the physical VSSL device when setting a property and once feedback has been received, the classes internal state will be updated. For example:
131
178
 
132
179
  ```python
133
- # Setting the zones name
180
+ # Setting the zone name
134
181
  zone1.settings.name = 'Living Room'
135
- >>> None
182
+ >>> 'Old Zone Name'
136
183
 
137
184
  # Printing zone name
138
- zone_name = zone1.settings.name
139
- print(zone_name)
185
+ print(zone1.settings.name)
140
186
  >>> 'Living Room'
141
187
  ```
142
188
 
143
- **Important** in the above example, `zone1.settings.name` wont be set to its new value until after the VSSL device has changed the name and the `Zone` class has received confirmation feedback. If you need to wait for the value change, you can await a `[property_name]_CHANGE` events.
189
+ **Important** in the above example, `zone1.settings.name` won't be set to its new value until after the VSSL device has changed the name and the `Zone` class has received confirmation feedback. If you need to wait for the value change, you can await a `[property_name]_CHANGE` events as below:
190
+
191
+ ```python
192
+ from vsslctrl.settings import ZoneSettings
193
+ # Setting the zone name and wait for feedback
194
+ future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.id)
195
+ zone1.settings.name = 'Bathroom'
196
+ # Helper to await a future with timeout
197
+ new_name = await vssl.event_bus.wait_future(future_name)
198
+ # Printing zone name
199
+ print(new_name)
200
+ >>> 'Bathroom'
201
+ # or
202
+ print(zone1.settings.name)
203
+ >>> 'Bathroom'
204
+ ```
205
+
206
+ # API Reference
207
+
208
+ # `DeviceModels`
209
+
210
+ A device model has to be passed to VSSL so it knows internally what features are supported by the device.
211
+ This might be removed in the future if we can differentiate different models from the API.
212
+
213
+ | Property | Description |
214
+ | ------------|--------- |
215
+ | `A1X` | A.1x |
216
+ | `A3X` | A.3x |
217
+ | `A6X` | A.6x |
218
+ | `A1` | A1 |
219
+ | `A3` | A3 |
220
+ | `A6` | A6 |
221
+
222
+ # `ZoneIDs`
223
+
224
+ A `ZoneIDs` must be passed to each `zone` you which to control and it must match the zone on the VSSL device.
225
+
226
+ If you are unsure of your `ZoneIDs` you could use the discovery helper to find out the correct mapping.
227
+
228
+ | Property | Description | A.1(x) | A.3(x) | A.6(x)
229
+ | ------------|--------- |-------- | -------- | -------- |
230
+ | `A1` | |✔️ | | |
231
+ | `ZONE_1` | Zone 1 | | ✔️| ✔️|
232
+ | `ZONE_2` | Zone 2 | | ✔️| ✔️|
233
+ | `ZONE_3` | Zone 3 | | ✔️| ✔️|
234
+ | `ZONE_4` | Zone 4 | | | ✔️|
235
+ | `ZONE_5` | Zone 5 | | | ✔️|
236
+ | `ZONE_6` | Zone 6 | | | ✔️|
144
237
 
145
238
 
146
239
  # `Vssl`
@@ -164,7 +257,7 @@ vssl.factory_reset()
164
257
 
165
258
  ## `Vssl.settings`
166
259
 
167
- | Property | Description | Type | Notes / Defaults |
260
+ | Property | Description | Type | Model: Default |
168
261
  | ---------------------- | ----------- | ----------- | ----------- |
169
262
  | `name` | Device name | `str` |
170
263
  | `bus_1_name` | Name of Bus 1 | `str` | <ul><li>A.1: Optical Input</li><li>A.3x/6x: Not Used</li></ul>
@@ -313,13 +406,13 @@ Input `InputRouter.Priorities` still apply.
313
406
  # Change zone 1 to listen to analog input 4
314
407
  zone1.input.source = InputRouter.Sources.ANALOG_IN_4
315
408
 
316
- # Change zone 1 to perfer analog input (local) over stream
409
+ # Change zone 1 to perfer local inputs over stream
317
410
  zone1.input.priority = InputRouter.Priorities.LOCAL
318
411
  ```
319
412
 
320
413
  ## `Zone.group`
321
414
 
322
- Officially unsupported in X series amplifiers.
415
+ Unsupported on X series amplifiers.
323
416
 
324
417
  | Property | Description | Type | Values |
325
418
  | ---------------------- | ----------- | ----------- |----------- |
@@ -458,55 +551,6 @@ zone1.settings.eq.khz1_db = -2
458
551
  zone1.settings.subwoofer.crossover = 100
459
552
  ```
460
553
 
461
-
462
-
463
- ## Another (Lite) Way
464
-
465
- If you perfer to not run the complete intergration, you can send basic HEX commands to the VSSL device using [Netcat](https://nc110.sourceforge.io/) (or any network tool) on port `50002`.
466
-
467
- | HEX | Description |
468
- | ---------------------- | ----------- |
469
- | `\x10\x05\x03\x0{Zone Number}\xff\x03` | Volume Up
470
- | `\x10\x05\x03\x0{Zone Number}\xfe\x03` | Volume Down
471
- | `\x10\x11\x02\x0{Zone Number}\x01` | Mute
472
- | All commands can be found by looking [here](https://github.com/vsslctrl/vsslctrl/blob/2c43c2f2393b94bc0e062d2ab90144343eca16ef/vsslctrl/api_alpha.py) |
473
-
474
-
475
- The `volume up` HEX command for `Zone 2` would be `\x10\x05\x03\x02\xff\x03`
476
-
477
- Now send the raw HEX using Netcat to the device using this syntax:
478
-
479
- `echo -e "{HEX Command}" | nc {IP Address} 50002`
480
-
481
- For example to send `volume up` to `Zone 2`:
482
-
483
- `echo -e "\x10\x05\x03\x02\xff\x03" | nc 192.168.1.11 50002`
484
-
485
- Home Assistant `Configuration.yaml` example:
486
-
487
- ```ymal
488
- ...
489
-
490
- shell_command:
491
- #Zone 1
492
- vssl_zone_1_volume_up: 'echo -e "\x10\x05\x03\x01\xff\x03" | nc 192.168.1.10 50002'
493
- vssl_zone_1_volume_down: 'echo -e "\x10\x05\x03\x01\xfe\x03" | nc 192.168.1.10 50002'
494
- vssl_zone_1_mute: 'echo -e "\x10\x11\x02\x01\x01" | nc 192.168.1.10 50002'
495
- vssl_zone_1_unmute: 'echo -e "\x10\x11\x02\x01\x00" | nc 192.168.1.10 50002'
496
- #Zone 2
497
- vssl_zone_2_volume_up: 'echo -e "\x10\x05\x03\x02\xff\x03" | nc 192.168.1.11 50002'
498
- vssl_zone_2_volume_down: 'echo -e "\x10\x05\x03\x02\xfe\x03" | nc 192.168.1.11 50002'
499
- vssl_zone_2_mute: 'echo -e "\x10\x11\x02\x02\x01" | nc 192.168.1.11 50002'
500
- vssl_zone_2_unmute: 'echo -e "\x10\x11\x02\x02\x00" | nc 192.168.1.11 50002'
501
- #Zone 3
502
- vssl_zone_3_volume_up: 'echo -e "\x10\x05\x03\x03\xff\x03" | nc 192.168.1.12 50002'
503
- vssl_zone_3_volume_down: 'echo -e "\x10\x05\x03\x03\xfe\x03" | nc 192.168.1.12 50002'
504
- vssl_zone_3_mute: 'echo -e "\x10\x11\x02\x03\x01" | nc 192.168.1.12 50002'
505
- vssl_zone_3_unmute: 'echo -e "\x10\x11\x02\x03\x00" | nc 192.168.1.12 50002'
506
-
507
- ...
508
- ```
509
-
510
554
  ## Credit
511
555
 
512
556
  Thanks to [@dj-jam](https://github.com/dj-jam) for the continued testing.
@@ -520,17 +564,9 @@ Motivation for this project was to integrate VSSLs amplifiers into [Home Assista
520
564
  * Not tested on A.1x or original A series range of amplifiers (testers welcome)
521
565
  * VSSL can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
522
566
  * Not all sources set the volume to 0 when the zone is muted
523
- * Grouping feedback is flaky on the X series amplifiers
524
567
  * Airplay `Zone.track.progress` is not available.
525
568
  * Cant stop a URL playback, feedback is worng at least
526
569
  * VSSL likes to cache old track metadata. For example when playing a URL after Spotify, often the device will respond with the previous (Spotify) tracks metadata
527
570
  * `stop()` is intended to disconnect the client and pause the stream. Doesn’t always function this way, depending on stream source
528
571
  * Occasionally a zones might stop responding to certain commands, issuing the `reboot` command generally corrects
529
572
 
530
- ## Future
531
-
532
- * A.1(x) coverage i.e Bluetooth
533
- * REST API / Web App
534
- * Save and recall EQ
535
- * IR Control
536
-
@@ -1,31 +1,43 @@
1
1
  # vsslctrl
2
2
 
3
- Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
3
+ Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
4
4
 
5
- **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
5
+ ## Coverage
6
6
 
7
- ## Help
7
+ Tested on:
8
8
 
9
- I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
9
+ | Model | Software Version | Note |
10
+ | ------------|--------- | -------------
11
+ | A.3x | p15305.016.3701 |
10
12
 
11
- Tested on:
12
- - **A.3x** software version **p15305.016.3701**
13
13
 
14
14
  Home Assistant [integration](https://github.com/vsslctrl/integration.home-assistant) with basic functionality working on:
15
- - **A.1** software version **p15265.033.3703** (reported)
16
- - **A.3** software version **p12013.141.3703** (reported)
17
- - **A.3x** software version **p15305.016.3701**
18
- - **A.6x** software version **p15305.017.3701** (reported)
15
+
16
+ | Model | Software Version | User Reported |
17
+ | ------------|--------- | -------------
18
+ | A.1 | p15265.033.3703 | ✔️
19
+ | A.3 | p12013.141.3703 | ✔️
20
+ | A.3x | p15305.016.3701 |
21
+ | A.6x | p15305.017.3701 | ✔️
22
+
23
+
24
+ ## Testers Needed
25
+
26
+ I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
27
+
28
+
19
29
 
20
30
  ## Important
21
31
 
22
- There should not be any *[VSSL Agent's](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* running on the same network. If you dont know what this is, then you can ignore this notice.
32
+ There should not be any *[VSSL Agent's](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* running on the network. If you dont know what this is, then you can ignore this notice.
33
+
34
+ **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
23
35
 
24
36
  ## TODOs
25
37
 
26
- * Correct IO mapping between models and versions
27
38
  * Better test coverage
28
- * A.1(x) testing
39
+ * A.1(x) testing - e.g output settings
40
+ * More controls - e.g IR Control
29
41
 
30
42
  ## Basic Usage
31
43
 
@@ -41,9 +53,9 @@ async def main():
41
53
 
42
54
  # Represents a physical VSSL amplifier
43
55
  vssl = Vssl(DeviceModels.A1)
44
- a1 = vssl.add_zone(ZoneIDs.A1, '192.168.1.10')
56
+ a1 = vssl.add_zone('192.168.1.10')
45
57
 
46
- # Connect and initiate zones.
58
+ # Connect and initialise zone.
47
59
  await vssl.initialise()
48
60
 
49
61
  """Control Examples"""
@@ -71,16 +83,15 @@ from vsslctrl import Vssl, DeviceModels, Zone, ZoneIDs
71
83
  async def main():
72
84
 
73
85
  # Represents a physical VSSL amplifier
74
- # If no DeviceModels is passed, vsslctrl will default to the feature set of the X series amps
75
86
  vssl = Vssl(DeviceModels.A3X)
76
87
 
77
88
  # Add each you wish to control
78
- zone1 = vssl.add_zone(ZoneIDs.ZONE_1, '192.168.1.10')
79
- zone2 = vssl.add_zone(ZoneIDs.ZONE_2, '192.168.1.11')
80
- zone3 = vssl.add_zone(ZoneIDs.ZONE_3, '192.168.1.12')
81
- #... up to 6 zones
89
+ zone1 = vssl.add_zone('192.168.1.10', ZoneIDs.ZONE_1)
90
+ zone2 = vssl.add_zone('192.168.1.11', ZoneIDs.ZONE_2)
91
+ zone3 = vssl.add_zone('192.168.1.12', ZoneIDs.ZONE_3)
92
+ #... up to 6 zones for A.6(x)
82
93
 
83
- # Connect and initiate zones.
94
+ # Connect and initialise zones.
84
95
  await vssl.initialise()
85
96
 
86
97
  """Control Examples"""
@@ -102,24 +113,106 @@ async def main():
102
113
  asyncio.run(main())
103
114
  ```
104
115
 
105
- # API
116
+ ### Device Discovery Helper
117
+
118
+ You can discover VSSL devices on the network using [mDNS](https://wikipedia.org/wiki/Multicast_DNS) / Bonjour if you have the [`zeroconf`](https://pypi.org/project/zeroconf/) package installed.
119
+
120
+ This uses airplay service string `_airplay._tcp.local.`, therefore airplay needs to available and will not work across VLANs without other provisions.
106
121
 
107
- Most functionality is achived via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
122
+ **Note:** This is designed to be a helper and its not recommended to be used for the initialization of the VSSL class.
123
+
124
+ ```python
125
+ import asyncio
126
+ from vsslctrl import Vssl
127
+
128
+ async def main():
129
+
130
+ print(await Vssl.discover())
131
+
132
+ """
133
+ {
134
+ 'XXXXXXXXXXXX': [
135
+ {
136
+ 'host': '192.168.168.25',
137
+ 'name': 'Living Room',
138
+ 'model': 'A1x',
139
+ 'mac_addr': 'AA:BB:CC:DD:EE:FF',
140
+ 'zone_id': '7',
141
+ 'serial': 'XXXXXXXXXXXX'
142
+ }
143
+ ]
144
+ }
145
+
146
+ """
147
+
148
+ asyncio.run(main())
149
+ ```
150
+
151
+
152
+ # API Functionality
153
+
154
+ Most functionality is achieved via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
108
155
 
109
156
  The classes will update the physical VSSL device when setting a property and once feedback has been received, the classes internal state will be updated. For example:
110
157
 
111
158
  ```python
112
- # Setting the zones name
159
+ # Setting the zone name
113
160
  zone1.settings.name = 'Living Room'
114
- >>> None
161
+ >>> 'Old Zone Name'
115
162
 
116
163
  # Printing zone name
117
- zone_name = zone1.settings.name
118
- print(zone_name)
164
+ print(zone1.settings.name)
119
165
  >>> 'Living Room'
120
166
  ```
121
167
 
122
- **Important** in the above example, `zone1.settings.name` wont be set to its new value until after the VSSL device has changed the name and the `Zone` class has received confirmation feedback. If you need to wait for the value change, you can await a `[property_name]_CHANGE` events.
168
+ **Important** in the above example, `zone1.settings.name` won't be set to its new value until after the VSSL device has changed the name and the `Zone` class has received confirmation feedback. If you need to wait for the value change, you can await a `[property_name]_CHANGE` events as below:
169
+
170
+ ```python
171
+ from vsslctrl.settings import ZoneSettings
172
+ # Setting the zone name and wait for feedback
173
+ future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.id)
174
+ zone1.settings.name = 'Bathroom'
175
+ # Helper to await a future with timeout
176
+ new_name = await vssl.event_bus.wait_future(future_name)
177
+ # Printing zone name
178
+ print(new_name)
179
+ >>> 'Bathroom'
180
+ # or
181
+ print(zone1.settings.name)
182
+ >>> 'Bathroom'
183
+ ```
184
+
185
+ # API Reference
186
+
187
+ # `DeviceModels`
188
+
189
+ A device model has to be passed to VSSL so it knows internally what features are supported by the device.
190
+ This might be removed in the future if we can differentiate different models from the API.
191
+
192
+ | Property | Description |
193
+ | ------------|--------- |
194
+ | `A1X` | A.1x |
195
+ | `A3X` | A.3x |
196
+ | `A6X` | A.6x |
197
+ | `A1` | A1 |
198
+ | `A3` | A3 |
199
+ | `A6` | A6 |
200
+
201
+ # `ZoneIDs`
202
+
203
+ A `ZoneIDs` must be passed to each `zone` you which to control and it must match the zone on the VSSL device.
204
+
205
+ If you are unsure of your `ZoneIDs` you could use the discovery helper to find out the correct mapping.
206
+
207
+ | Property | Description | A.1(x) | A.3(x) | A.6(x)
208
+ | ------------|--------- |-------- | -------- | -------- |
209
+ | `A1` | |✔️ | | |
210
+ | `ZONE_1` | Zone 1 | | ✔️| ✔️|
211
+ | `ZONE_2` | Zone 2 | | ✔️| ✔️|
212
+ | `ZONE_3` | Zone 3 | | ✔️| ✔️|
213
+ | `ZONE_4` | Zone 4 | | | ✔️|
214
+ | `ZONE_5` | Zone 5 | | | ✔️|
215
+ | `ZONE_6` | Zone 6 | | | ✔️|
123
216
 
124
217
 
125
218
  # `Vssl`
@@ -143,7 +236,7 @@ vssl.factory_reset()
143
236
 
144
237
  ## `Vssl.settings`
145
238
 
146
- | Property | Description | Type | Notes / Defaults |
239
+ | Property | Description | Type | Model: Default |
147
240
  | ---------------------- | ----------- | ----------- | ----------- |
148
241
  | `name` | Device name | `str` |
149
242
  | `bus_1_name` | Name of Bus 1 | `str` | <ul><li>A.1: Optical Input</li><li>A.3x/6x: Not Used</li></ul>
@@ -292,13 +385,13 @@ Input `InputRouter.Priorities` still apply.
292
385
  # Change zone 1 to listen to analog input 4
293
386
  zone1.input.source = InputRouter.Sources.ANALOG_IN_4
294
387
 
295
- # Change zone 1 to perfer analog input (local) over stream
388
+ # Change zone 1 to perfer local inputs over stream
296
389
  zone1.input.priority = InputRouter.Priorities.LOCAL
297
390
  ```
298
391
 
299
392
  ## `Zone.group`
300
393
 
301
- Officially unsupported in X series amplifiers.
394
+ Unsupported on X series amplifiers.
302
395
 
303
396
  | Property | Description | Type | Values |
304
397
  | ---------------------- | ----------- | ----------- |----------- |
@@ -437,55 +530,6 @@ zone1.settings.eq.khz1_db = -2
437
530
  zone1.settings.subwoofer.crossover = 100
438
531
  ```
439
532
 
440
-
441
-
442
- ## Another (Lite) Way
443
-
444
- If you perfer to not run the complete intergration, you can send basic HEX commands to the VSSL device using [Netcat](https://nc110.sourceforge.io/) (or any network tool) on port `50002`.
445
-
446
- | HEX | Description |
447
- | ---------------------- | ----------- |
448
- | `\x10\x05\x03\x0{Zone Number}\xff\x03` | Volume Up
449
- | `\x10\x05\x03\x0{Zone Number}\xfe\x03` | Volume Down
450
- | `\x10\x11\x02\x0{Zone Number}\x01` | Mute
451
- | All commands can be found by looking [here](https://github.com/vsslctrl/vsslctrl/blob/2c43c2f2393b94bc0e062d2ab90144343eca16ef/vsslctrl/api_alpha.py) |
452
-
453
-
454
- The `volume up` HEX command for `Zone 2` would be `\x10\x05\x03\x02\xff\x03`
455
-
456
- Now send the raw HEX using Netcat to the device using this syntax:
457
-
458
- `echo -e "{HEX Command}" | nc {IP Address} 50002`
459
-
460
- For example to send `volume up` to `Zone 2`:
461
-
462
- `echo -e "\x10\x05\x03\x02\xff\x03" | nc 192.168.1.11 50002`
463
-
464
- Home Assistant `Configuration.yaml` example:
465
-
466
- ```ymal
467
- ...
468
-
469
- shell_command:
470
- #Zone 1
471
- vssl_zone_1_volume_up: 'echo -e "\x10\x05\x03\x01\xff\x03" | nc 192.168.1.10 50002'
472
- vssl_zone_1_volume_down: 'echo -e "\x10\x05\x03\x01\xfe\x03" | nc 192.168.1.10 50002'
473
- vssl_zone_1_mute: 'echo -e "\x10\x11\x02\x01\x01" | nc 192.168.1.10 50002'
474
- vssl_zone_1_unmute: 'echo -e "\x10\x11\x02\x01\x00" | nc 192.168.1.10 50002'
475
- #Zone 2
476
- vssl_zone_2_volume_up: 'echo -e "\x10\x05\x03\x02\xff\x03" | nc 192.168.1.11 50002'
477
- vssl_zone_2_volume_down: 'echo -e "\x10\x05\x03\x02\xfe\x03" | nc 192.168.1.11 50002'
478
- vssl_zone_2_mute: 'echo -e "\x10\x11\x02\x02\x01" | nc 192.168.1.11 50002'
479
- vssl_zone_2_unmute: 'echo -e "\x10\x11\x02\x02\x00" | nc 192.168.1.11 50002'
480
- #Zone 3
481
- vssl_zone_3_volume_up: 'echo -e "\x10\x05\x03\x03\xff\x03" | nc 192.168.1.12 50002'
482
- vssl_zone_3_volume_down: 'echo -e "\x10\x05\x03\x03\xfe\x03" | nc 192.168.1.12 50002'
483
- vssl_zone_3_mute: 'echo -e "\x10\x11\x02\x03\x01" | nc 192.168.1.12 50002'
484
- vssl_zone_3_unmute: 'echo -e "\x10\x11\x02\x03\x00" | nc 192.168.1.12 50002'
485
-
486
- ...
487
- ```
488
-
489
533
  ## Credit
490
534
 
491
535
  Thanks to [@dj-jam](https://github.com/dj-jam) for the continued testing.
@@ -499,17 +543,9 @@ Motivation for this project was to integrate VSSLs amplifiers into [Home Assista
499
543
  * Not tested on A.1x or original A series range of amplifiers (testers welcome)
500
544
  * VSSL can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
501
545
  * Not all sources set the volume to 0 when the zone is muted
502
- * Grouping feedback is flaky on the X series amplifiers
503
546
  * Airplay `Zone.track.progress` is not available.
504
547
  * Cant stop a URL playback, feedback is worng at least
505
548
  * VSSL likes to cache old track metadata. For example when playing a URL after Spotify, often the device will respond with the previous (Spotify) tracks metadata
506
549
  * `stop()` is intended to disconnect the client and pause the stream. Doesn’t always function this way, depending on stream source
507
550
  * Occasionally a zones might stop responding to certain commands, issuing the `reboot` command generally corrects
508
551
 
509
- ## Future
510
-
511
- * A.1(x) coverage i.e Bluetooth
512
- * REST API / Web App
513
- * Save and recall EQ
514
- * IR Control
515
-
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vsslctrl"
7
- version = "0.1.11.dev1"
7
+ version = "0.1.13.dev1"
8
8
  description = "Package for controlling VSSL's range of streaming amplifiers"
9
9
  authors = [
10
10
  { name="vsslctrl", email="vsslcontrolled@proton.me" },