vsslctrl 0.1.5.dev1__tar.gz → 0.1.7.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 (32) hide show
  1. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/PKG-INFO +47 -48
  2. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/README.md +45 -46
  3. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/pyproject.toml +2 -2
  4. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/api_alpha.py +25 -25
  5. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/api_bravo.py +5 -3
  6. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/core.py +1 -1
  7. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/data_structure.py +57 -1
  8. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/device.py +3 -2
  9. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/io.py +4 -4
  10. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/settings.py +90 -1
  11. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/utils.py +13 -0
  12. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/zone.py +9 -2
  13. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl.egg-info/PKG-INFO +47 -48
  14. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/LICENSE +0 -0
  15. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/setup.cfg +0 -0
  16. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/tests/test_event_bus.py +0 -0
  17. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/tests/test_integration.py +0 -0
  18. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/tests/test_settings.py +0 -0
  19. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/tests/test_zone.py +0 -0
  20. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/__init__.py +0 -0
  21. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/api_base.py +0 -0
  22. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/decorators.py +0 -0
  23. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/discovery.py +0 -0
  24. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/event_bus.py +0 -0
  25. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/exceptions.py +0 -0
  26. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/group.py +0 -0
  27. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/track.py +0 -0
  28. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl/transport.py +0 -0
  29. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl.egg-info/SOURCES.txt +0 -0
  30. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl.egg-info/dependency_links.txt +0 -0
  31. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl.egg-info/requires.txt +0 -0
  32. {vsslctrl-0.1.5.dev1 → vsslctrl-0.1.7.dev1}/vsslctrl.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vsslctrl
3
- Version: 0.1.5.dev1
4
- Summary: Package for controlling VSSL amplifiers
3
+ Version: 0.1.7.dev1
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
7
7
  Classifier: Programming Language :: Python :: 3
@@ -20,31 +20,30 @@ Provides-Extra: optional
20
20
  Requires-Dist: zeroconf==0.132.2; extra == "optional"
21
21
 
22
22
  # vsslctrl
23
- Package for controlling [VSSL](https://www.vssl.com/) range of streaming amplifiers.
23
+
24
+ Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
24
25
 
25
26
  **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
26
27
 
27
- Motovation for this project was to intergrate VSSLs amplifiers into [Home Assistant](https://www.home-assistant.io/) and have control over different subnets (not mDNS dependant)
28
+ ## Help
28
29
 
29
- I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping.
30
+ I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
30
31
 
31
- Important
32
- -----------
33
- Only tested on a VSSL **A.3x** software version **p15305.016.3701**.
32
+ Tested on:
33
+ - Test suite run on a VSSL **A.3x** software version **p15305.016.3701**
34
+ - The Home Assistant [integration](https://github.com/vsslctrl/integration.home-assistant) is reported working on a **A.6x** software version **p15305.017.3701**
34
35
 
35
- **Notice:** VSSLs new iOS app titled `VSSL`can cause connection refused issues if running at the same time as `vsslctrl`. Best to not use the iOS app togeather. The `VSSL Legacy` app works fine
36
+ ## Important
36
37
 
37
- **Warning:** no *[VSSL Agent](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* should be running on the same network. If you dont know what this is, then you can probably ignore this notice.
38
+ 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.
38
39
 
39
40
  ## TODOs
40
41
 
41
- * Test on other models (hardware needed)
42
- * Home Assistant integration. In progress, [here](https://github.com/vsslctrl/integration.home-assistant)
43
- * ~~Function scoping to supported feature / models~~ (needs tests)
42
+ * **A1(.x)** specific control e.g sub crossover, bluetooth
44
43
  * Better test coverage
45
44
 
46
- Basic Usage
47
- -----------
45
+ ## Basic Usage
46
+
48
47
  `vsslctrl` needs to be running inside a **[asyncio](https://docs.python.org/3/library/asyncio.html)** event loop.
49
48
 
50
49
  ```python
@@ -91,8 +90,7 @@ async def main():
91
90
  asyncio.run(main())
92
91
  ```
93
92
 
94
- API
95
- -----------
93
+ # API
96
94
 
97
95
  Most functionality is achived via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
98
96
 
@@ -284,10 +282,10 @@ zone1.group.dissolve()
284
282
 
285
283
  ## `Zone.analog_output`
286
284
 
287
- | Property | Description | Type | Values |
288
- | ---------------------- | ----------- | ----------- |----------- |
289
- | `source` | Where the AO is routed from. i.e a zone, optical input or off | `int` | `AnalogOutput.Sources`
290
- | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` readonly
285
+ | Property | Description | Type | Values | Default |
286
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
287
+ | `source` | Where the AO is routed from. i.e a zone, optical input or off | `int` | `AnalogOutput.Sources` | `Off`
288
+ | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` | |`False`
291
289
  | `is_fixed_volume_toggle()` | Toggle fixed volume | `func` |
292
290
 
293
291
  ```python
@@ -304,12 +302,12 @@ zone1.analog_output.is_fixed_volume = True
304
302
 
305
303
  ## `Zone.settings`
306
304
 
307
- | Property | Description | Type | Values |
308
- | ---------------------- | ----------- | ----------- |----------- |
305
+ | Property | Description | Type | Values | Default |
306
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
309
307
  | `name` | Name | `str` |
310
- | `disabled` | Disable the zone | `bool`
308
+ | `disabled` | Disable the zone | `bool` || `False`
311
309
  | `disabled_toggle()` | disable / enable | `func` |
312
- | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono`
310
+ | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono` | `Stereo`
313
311
  | `mono_toggle()` | Toggle mono or stereo | `func` |
314
312
 
315
313
  ```python
@@ -324,10 +322,10 @@ zone1.mono_toggle()
324
322
 
325
323
  ## `Zone.settings.analog_input`
326
324
 
327
- | Property | Description | Type | Values |
328
- | ---------------------- | ----------- | ----------- |----------- |
325
+ | Property | Description | Type | Values | Default |
326
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
329
327
  | `name` | Name | `str` |
330
- | `fixed_gain` | Fix the input gain to a specific value |`int` | `0...100`
328
+ | `fixed_gain` | Fix the input gain to a specific value |`int` | `0...100` | `0` is disabled or variable gain
331
329
 
332
330
  ```python
333
331
  """Examples"""
@@ -341,11 +339,11 @@ zone1.settings.analog_input.fixed_gain = 50
341
339
 
342
340
  ## `Zone.settings.volume`
343
341
 
344
- | Property | Description | Type | Values |
345
- | ---------------------- | ----------- | ----------- |----------- |
346
- | `default_on` | Default on volume | `int` | `0...100`
347
- | `max_left` | Max volume left channel | `int` | `0...100`
348
- | `max_right` | Max volume right channel | `int` | `0...100`
342
+ | Property | Description | Type | Values | Default |
343
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
344
+ | `default_on` | Default on volume | `int` | `0...100` | `0` is disabled
345
+ | `max_left` | Max volume left channel | `int` | `0...100` | `75`
346
+ | `max_right` | Max volume right channel | `int` | `0...100` | `75`
349
347
 
350
348
  ```python
351
349
  """Examples"""
@@ -357,21 +355,21 @@ zone1.settings.volume.default_on = 75
357
355
 
358
356
  ## `Zone.settings.eq`
359
357
 
360
- | Property | Description | Type | Values |
361
- | ---------------------- | ----------- | ----------- |----------- |
362
- | `enabled` | Enable / disable EQ | `bool`
358
+ | Property | Description | Type | Values | Default |
359
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
360
+ | `enabled` | Enable / disable EQ | `bool` | | `False`
363
361
 
364
362
  EQ to be set in [decibel](https://en.wikipedia.org/wiki/Decibel) using a range `-10`dB to `+10`dB
365
363
 
366
- | Property | Description | Type | Values |
367
- | ---------------------- | ----------- | ----------- |----------- |
368
- | `hz60_db` | 60Hz | `int` | `-10...10`
369
- | `hz200_db` | 200Hz | `int` | `-10...10`
370
- | `hz500_db` | 500Hz | `int` | `-10...10`
371
- | `khz1_db` | 1kHz | `int` | `-10...10`
372
- | `khz4_db` | 4kHz | `int` | `-10...10`
373
- | `khz8_db` | 8kHz | `int` | `-10...10`
374
- | `khz15_db` | 15kHz | `int` | `-10...10`
364
+ | Property | Description | Type | Values | Default |
365
+ | ---------------------- | ----------- | ----------- |----------- | ----------- |
366
+ | `hz60_db` | 60Hz | `int` | `-10...10` | `0`
367
+ | `hz200_db` | 200Hz | `int` | `-10...10` | `0`
368
+ | `hz500_db` | 500Hz | `int` | `-10...10` | `0`
369
+ | `khz1_db` | 1kHz | `int` | `-10...10` | `0`
370
+ | `khz4_db` | 4kHz | `int` | `-10...10` | `0`
371
+ | `khz8_db` | 8kHz | `int` | `-10...10` | `0`
372
+ | `khz15_db` | 15kHz | `int` | `-10...10` | `0`
375
373
 
376
374
  ```python
377
375
  """Examples"""
@@ -430,10 +428,11 @@ shell_command:
430
428
 
431
429
  The VSSL API was reverse engineered using Wireshark, VSSLs native "legacy" iOS app and their deprecated [vsslagent](https://vssl.gitbook.io/vssl-rest-api/getting-started/start).
432
430
 
431
+ Motovation for this project was to intergrate VSSLs amplifiers into [Home Assistant](https://www.home-assistant.io/) and have control over different subnets (not mDNS dependant)
432
+
433
433
  ## Known Issues & Limitiations
434
434
 
435
- * Tested on VSSL **A.3x** software version **p15305.016.3701**
436
- * Not tested on A.1x, A.6.x or original A series range of amplifiers (testers welcome)
435
+ * Not tested on A.1x or original A series range of amplifiers (testers welcome)
437
436
  * VSSL can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
438
437
  * Not all sources set the volume to 0 when the zone is muted
439
438
  * Grouping feedback is flaky on the X series amplifiers
@@ -445,8 +444,8 @@ The VSSL API was reverse engineered using Wireshark, VSSLs native "legacy" iOS a
445
444
 
446
445
  ## Future
447
446
 
447
+ * A.1(x) coverage i.e Bluetooth and subwoofer control
448
448
  * REST API / Web App
449
449
  * Save and recall EQ
450
- * A.1(x) coverage i.e Bluetooth
451
450
  * IR Control
452
451
 
@@ -1,29 +1,28 @@
1
1
  # vsslctrl
2
- Package for controlling [VSSL](https://www.vssl.com/) range of streaming amplifiers.
2
+
3
+ Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
3
4
 
4
5
  **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
5
6
 
6
- Motovation for this project was to intergrate VSSLs amplifiers into [Home Assistant](https://www.home-assistant.io/) and have control over different subnets (not mDNS dependant)
7
+ ## Help
7
8
 
8
- I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping.
9
+ I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
9
10
 
10
- Important
11
- -----------
12
- Only tested on a VSSL **A.3x** software version **p15305.016.3701**.
11
+ Tested on:
12
+ - Test suite run on a VSSL **A.3x** software version **p15305.016.3701**
13
+ - The Home Assistant [integration](https://github.com/vsslctrl/integration.home-assistant) is reported working on a **A.6x** software version **p15305.017.3701**
13
14
 
14
- **Notice:** VSSLs new iOS app titled `VSSL`can cause connection refused issues if running at the same time as `vsslctrl`. Best to not use the iOS app togeather. The `VSSL Legacy` app works fine
15
+ ## Important
15
16
 
16
- **Warning:** no *[VSSL Agent](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* should be running on the same network. If you dont know what this is, then you can probably ignore this notice.
17
+ 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.
17
18
 
18
19
  ## TODOs
19
20
 
20
- * Test on other models (hardware needed)
21
- * Home Assistant integration. In progress, [here](https://github.com/vsslctrl/integration.home-assistant)
22
- * ~~Function scoping to supported feature / models~~ (needs tests)
21
+ * **A1(.x)** specific control e.g sub crossover, bluetooth
23
22
  * Better test coverage
24
23
 
25
- Basic Usage
26
- -----------
24
+ ## Basic Usage
25
+
27
26
  `vsslctrl` needs to be running inside a **[asyncio](https://docs.python.org/3/library/asyncio.html)** event loop.
28
27
 
29
28
  ```python
@@ -70,8 +69,7 @@ async def main():
70
69
  asyncio.run(main())
71
70
  ```
72
71
 
73
- API
74
- -----------
72
+ # API
75
73
 
76
74
  Most functionality is achived via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
77
75
 
@@ -263,10 +261,10 @@ zone1.group.dissolve()
263
261
 
264
262
  ## `Zone.analog_output`
265
263
 
266
- | Property | Description | Type | Values |
267
- | ---------------------- | ----------- | ----------- |----------- |
268
- | `source` | Where the AO is routed from. i.e a zone, optical input or off | `int` | `AnalogOutput.Sources`
269
- | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` readonly
264
+ | Property | Description | Type | Values | Default |
265
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
266
+ | `source` | Where the AO is routed from. i.e a zone, optical input or off | `int` | `AnalogOutput.Sources` | `Off`
267
+ | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` | |`False`
270
268
  | `is_fixed_volume_toggle()` | Toggle fixed volume | `func` |
271
269
 
272
270
  ```python
@@ -283,12 +281,12 @@ zone1.analog_output.is_fixed_volume = True
283
281
 
284
282
  ## `Zone.settings`
285
283
 
286
- | Property | Description | Type | Values |
287
- | ---------------------- | ----------- | ----------- |----------- |
284
+ | Property | Description | Type | Values | Default |
285
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
288
286
  | `name` | Name | `str` |
289
- | `disabled` | Disable the zone | `bool`
287
+ | `disabled` | Disable the zone | `bool` || `False`
290
288
  | `disabled_toggle()` | disable / enable | `func` |
291
- | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono`
289
+ | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono` | `Stereo`
292
290
  | `mono_toggle()` | Toggle mono or stereo | `func` |
293
291
 
294
292
  ```python
@@ -303,10 +301,10 @@ zone1.mono_toggle()
303
301
 
304
302
  ## `Zone.settings.analog_input`
305
303
 
306
- | Property | Description | Type | Values |
307
- | ---------------------- | ----------- | ----------- |----------- |
304
+ | Property | Description | Type | Values | Default |
305
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
308
306
  | `name` | Name | `str` |
309
- | `fixed_gain` | Fix the input gain to a specific value |`int` | `0...100`
307
+ | `fixed_gain` | Fix the input gain to a specific value |`int` | `0...100` | `0` is disabled or variable gain
310
308
 
311
309
  ```python
312
310
  """Examples"""
@@ -320,11 +318,11 @@ zone1.settings.analog_input.fixed_gain = 50
320
318
 
321
319
  ## `Zone.settings.volume`
322
320
 
323
- | Property | Description | Type | Values |
324
- | ---------------------- | ----------- | ----------- |----------- |
325
- | `default_on` | Default on volume | `int` | `0...100`
326
- | `max_left` | Max volume left channel | `int` | `0...100`
327
- | `max_right` | Max volume right channel | `int` | `0...100`
321
+ | Property | Description | Type | Values | Default |
322
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
323
+ | `default_on` | Default on volume | `int` | `0...100` | `0` is disabled
324
+ | `max_left` | Max volume left channel | `int` | `0...100` | `75`
325
+ | `max_right` | Max volume right channel | `int` | `0...100` | `75`
328
326
 
329
327
  ```python
330
328
  """Examples"""
@@ -336,21 +334,21 @@ zone1.settings.volume.default_on = 75
336
334
 
337
335
  ## `Zone.settings.eq`
338
336
 
339
- | Property | Description | Type | Values |
340
- | ---------------------- | ----------- | ----------- |----------- |
341
- | `enabled` | Enable / disable EQ | `bool`
337
+ | Property | Description | Type | Values | Default |
338
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
339
+ | `enabled` | Enable / disable EQ | `bool` | | `False`
342
340
 
343
341
  EQ to be set in [decibel](https://en.wikipedia.org/wiki/Decibel) using a range `-10`dB to `+10`dB
344
342
 
345
- | Property | Description | Type | Values |
346
- | ---------------------- | ----------- | ----------- |----------- |
347
- | `hz60_db` | 60Hz | `int` | `-10...10`
348
- | `hz200_db` | 200Hz | `int` | `-10...10`
349
- | `hz500_db` | 500Hz | `int` | `-10...10`
350
- | `khz1_db` | 1kHz | `int` | `-10...10`
351
- | `khz4_db` | 4kHz | `int` | `-10...10`
352
- | `khz8_db` | 8kHz | `int` | `-10...10`
353
- | `khz15_db` | 15kHz | `int` | `-10...10`
343
+ | Property | Description | Type | Values | Default |
344
+ | ---------------------- | ----------- | ----------- |----------- | ----------- |
345
+ | `hz60_db` | 60Hz | `int` | `-10...10` | `0`
346
+ | `hz200_db` | 200Hz | `int` | `-10...10` | `0`
347
+ | `hz500_db` | 500Hz | `int` | `-10...10` | `0`
348
+ | `khz1_db` | 1kHz | `int` | `-10...10` | `0`
349
+ | `khz4_db` | 4kHz | `int` | `-10...10` | `0`
350
+ | `khz8_db` | 8kHz | `int` | `-10...10` | `0`
351
+ | `khz15_db` | 15kHz | `int` | `-10...10` | `0`
354
352
 
355
353
  ```python
356
354
  """Examples"""
@@ -409,10 +407,11 @@ shell_command:
409
407
 
410
408
  The VSSL API was reverse engineered using Wireshark, VSSLs native "legacy" iOS app and their deprecated [vsslagent](https://vssl.gitbook.io/vssl-rest-api/getting-started/start).
411
409
 
410
+ Motovation for this project was to intergrate VSSLs amplifiers into [Home Assistant](https://www.home-assistant.io/) and have control over different subnets (not mDNS dependant)
411
+
412
412
  ## Known Issues & Limitiations
413
413
 
414
- * Tested on VSSL **A.3x** software version **p15305.016.3701**
415
- * Not tested on A.1x, A.6.x or original A series range of amplifiers (testers welcome)
414
+ * Not tested on A.1x or original A series range of amplifiers (testers welcome)
416
415
  * VSSL can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
417
416
  * Not all sources set the volume to 0 when the zone is muted
418
417
  * Grouping feedback is flaky on the X series amplifiers
@@ -424,8 +423,8 @@ The VSSL API was reverse engineered using Wireshark, VSSLs native "legacy" iOS a
424
423
 
425
424
  ## Future
426
425
 
426
+ * A.1(x) coverage i.e Bluetooth and subwoofer control
427
427
  * REST API / Web App
428
428
  * Save and recall EQ
429
- * A.1(x) coverage i.e Bluetooth
430
429
  * IR Control
431
430
 
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vsslctrl"
7
- version = "0.1.5.dev1"
8
- description = "Package for controlling VSSL amplifiers"
7
+ version = "0.1.7.dev1"
8
+ description = "Package for controlling VSSL's range of streaming amplifiers"
9
9
  authors = [
10
10
  { name="vsslctrl", email="vsslcontrolled@proton.me" },
11
11
  ]
@@ -9,13 +9,14 @@ from .api_base import APIBase
9
9
  from .transport import ZoneTransport
10
10
  from .settings import EQSettings
11
11
 
12
- from .utils import hex_to_int, clamp_volume
12
+ from .utils import hex_to_int, clamp_volume, hex_to_bytearray_string
13
13
  from .decorators import logging_helpers
14
14
  from .data_structure import (
15
15
  ZoneStatusExtKeys,
16
16
  ZoneEQStatusExtKeys,
17
17
  ZoneRouterStatusExtKeys,
18
18
  DeviceStatusExtKeys,
19
+ DeviceStatusExtendedExtKeys,
19
20
  )
20
21
 
21
22
 
@@ -94,10 +95,10 @@ class APIAlpha(APIBase):
94
95
 
95
96
  #
96
97
  # 00 [0] - 0B [11]
97
- # Status BT (Bluetooth)
98
+ # Status device extended
98
99
  #
99
100
  def request_action_00_0B(self):
100
- self._log_debug("Requesting status bluetooth")
101
+ self._log_debug("Requesting device status extended")
101
102
  self.send(bytearray([16, 0, 1, 11])) # HEX: 1000010B
102
103
 
103
104
  #
@@ -199,7 +200,7 @@ class APIAlpha(APIBase):
199
200
  # EQ
200
201
  #
201
202
  def request_action_0D(self, freq: "EQSettings.Freqs", value: int = 0):
202
- clamped = max(90, min(value, 110))
203
+ clamped = max(EQSettings.MIN_VALUE, min(value, EQSettings.MAX_VALUE))
203
204
  self._log_debug(
204
205
  f"Requesting to set EQ: {freq.name[1:]} ({freq.value}) to {clamped}"
205
206
  )
@@ -746,28 +747,25 @@ class APIAlpha(APIBase):
746
747
 
747
748
  #
748
749
  # 00_0B
749
- # System Status 0B (Not Sure)
750
+ # Device Status Extended 0B
750
751
  #
751
752
  # {'IRMskL': '241', 'IRMskH': '255', 'BTSta': '0', 'Crs': '0', 'Fes': '0', 'Drk': '0'}
752
753
  #
753
- #
754
- # IRMskL / IRMskH:
755
- # These could potentially be related to Infrared (IR) remote control signals. "IRMskL" and "IRMskH" might represent the low and high values of the modulation frequency or pulse width for an infrared signal.
756
- #
757
- # BTSta:
758
- # This might represent the Bluetooth status, with "0" indicating that Bluetooth is currently not active or disconnected.
759
- #
760
- # Crs:
761
- # It could stand for "Crossfade" and may represent a setting related to crossfading between audio tracks.
762
- #
763
- # Fes:
764
- # This might stand for "Frequency" or "Filter Effect Setting," representing a parameter related to frequency or filtering effects.
765
- #
766
- # Drk: ?
767
- #
768
754
  def response_action_00_0B(self, metadata: list):
769
755
  self._log_debug(f"Received 0B Status: {metadata}")
770
- pass
756
+
757
+ # Bluetooth
758
+ if DeviceStatusExtendedExtKeys.BLUETOOTH_STATUS in metadata:
759
+ self.vssl.settings._set_property(
760
+ "bluetooth", int(metadata[DeviceStatusExtendedExtKeys.BLUETOOTH_STATUS])
761
+ )
762
+
763
+ # Subwoofer Crossover
764
+ if DeviceStatusExtendedExtKeys.SUBWOOFER_CROSSOVER in metadata:
765
+ self.zone.settings.subwoofer._set_property(
766
+ "crossover",
767
+ int(metadata[DeviceStatusExtendedExtKeys.SUBWOOFER_CROSSOVER]),
768
+ )
771
769
 
772
770
  #
773
771
  # 2A [42]
@@ -924,9 +922,9 @@ class APIAlpha(APIBase):
924
922
 
925
923
  #
926
924
  # 17 [23]
927
- # Received Keep Alive
925
+ # Keep Alive
928
926
  #
929
- def response_action_17(self, response: bytes):
927
+ def response_action_17(self, hexl: list, response: bytes):
930
928
  self._log_debug(f"Z{self.zone.id} Alpha - Received keep alive: {response}")
931
929
  # TODO
932
930
  pass
@@ -1026,8 +1024,9 @@ class APIAlpha(APIBase):
1026
1024
  # Command confimation
1027
1025
  #
1028
1026
  def response_action_confimation(self, response: bytes):
1027
+ cmd = response.hex()
1029
1028
  self._log_debug(
1030
- f"Received command confimation: {response[1]}. Hex: {response.hex()}"
1029
+ f"Received command confimation: {hex_to_bytearray_string(cmd)} Hex: {cmd}"
1031
1030
  )
1032
1031
 
1033
1032
  #
@@ -1035,6 +1034,7 @@ class APIAlpha(APIBase):
1035
1034
  # Default Action
1036
1035
  #
1037
1036
  def response_action_default(self, hexl: list, response: bytes):
1037
+ cmd = response.hex()
1038
1038
  self._log_debug(
1039
- f"Received unknown command {hexl[1].upper()}. Hex: {response.hex()}"
1039
+ f"Received unknown command: {hex_to_bytearray_string(cmd)} Hex: {cmd}"
1040
1040
  )
@@ -5,7 +5,7 @@ import struct
5
5
  import logging
6
6
 
7
7
  from .api_base import APIBase
8
- from .utils import hex_to_int
8
+ from .utils import hex_to_int, hex_to_bytearray_string
9
9
  from .decorators import logging_helpers
10
10
  from .data_structure import TrackMetadataExtKeys
11
11
 
@@ -407,8 +407,10 @@ class APIBravo(APIBase):
407
407
  #
408
408
  def response_action_70(self, hexl: list, response: bytes):
409
409
  length = 4 if hexl[0] == 16 else 10
410
- cmd = hexl[length:]
411
- self._log_debug(f"Command confirmation: {response[length:]}")
410
+ cmd = response[length:].hex()
411
+ self._log_debug(
412
+ f"Received command confimation: {hex_to_bytearray_string(cmd)} Hex: {cmd}"
413
+ )
412
414
 
413
415
  #
414
416
  # Default
@@ -69,7 +69,7 @@ class Vssl:
69
69
  self.Events.MODEL_CHANGE, self.ENTITY_ID
70
70
  )
71
71
 
72
- # Lets make sure the zone is initialised, otherwsie we fail all
72
+ # Lets make sure the zone is initialised, otherwsie we fail for all zones
73
73
  await first_zone.initialise()
74
74
 
75
75
  # Only continue after we have a model
@@ -92,6 +92,57 @@ class DeviceStatusExtKeys:
92
92
  return f"B{zone_id}Src"
93
93
 
94
94
 
95
+ """
96
+ JSON Structure
97
+
98
+ DO NOT CHANGE - VSSL Defined
99
+
100
+
101
+ IRMskL / IRMskH:
102
+ These could potentially be related to Infrared (IR) remote control signals. "IRMskL" and "IRMskH" might represent the low and high values of the modulation frequency or pulse width for an infrared signal.
103
+
104
+ BTSta:
105
+ This might represent the Bluetooth status, with "0" indicating that Bluetooth is currently not active or disconnected.
106
+
107
+ Crs:
108
+ It could stand for "Crossfade" and may represent a setting related to crossfading between audio tracks.
109
+
110
+ Fes:
111
+ This might stand for "Frequency" or "Filter Effect Setting," representing a parameter related to frequency or filtering effects.
112
+
113
+ Drk: ?
114
+
115
+
116
+ A3.x
117
+ {
118
+ 'IRMskL': '241',
119
+ 'IRMskH': '255',
120
+ 'BTSta': '0',
121
+ 'Crs': '0',
122
+ 'Fes': '0',
123
+ 'Drk': '0'
124
+ }
125
+
126
+ A6.x
127
+ {
128
+ "IRMskL":"255",
129
+ "IRMskH":"255",
130
+ "BTSta":"0",
131
+ "Crs":"0",
132
+ "Fes":"0",
133
+ "Drk":"0"
134
+ '
135
+
136
+ """
137
+
138
+
139
+ class DeviceStatusExtendedExtKeys:
140
+ IR_HIGH = "IRMskH" # Guess - To Confirm
141
+ IR_LOW = "IRMskL" # Guess - To Confirm
142
+ BLUETOOTH_STATUS = "BTSta" # Guess - To Confirm
143
+ SUBWOOFER_CROSSOVER = "Crs" # Guess - To Confirm
144
+
145
+
95
146
  """
96
147
  JSON Structure
97
148
 
@@ -253,7 +304,12 @@ class ZoneRouterStatusExtKeys:
253
304
  EQ_ENABLED = "eqsw"
254
305
  INPUT_SOURCE = "inSrc"
255
306
  SOURCE_PRIORITY = "SP"
256
- ANALOG_OUTPUT_FIXED_VOLUME_PREFIX = "BF"
307
+ ANALOG_OUTPUT_1_FIXED_VOLUME = "BF1"
308
+ ANALOG_OUTPUT_2_FIXED_VOLUME = "BF2"
309
+ ANALOG_OUTPUT_3_FIXED_VOLUME = "BF3"
310
+ ANALOG_OUTPUT_4_FIXED_VOLUME = "BF4"
311
+ ANALOG_OUTPUT_5_FIXED_VOLUME = "BF5"
312
+ ANALOG_OUTPUT_6_FIXED_VOLUME = "BF6"
257
313
  GROUP_SOURCE = "GRS"
258
314
  GROUP_MASTER = "GRM"
259
315
  POWER_STATE = "Pwr"
@@ -36,6 +36,7 @@ class Features(VsslIntEnum):
36
36
  GROUPING = 1000
37
37
  BLUETOOTH = 1001
38
38
  PARTY_MODE = 1002
39
+ SUBWOOFER_CROSSOVER = 1003
39
40
 
40
41
 
41
42
  class Model:
@@ -65,7 +66,7 @@ class Models(VsslEnum):
65
66
  "zones": SINGLE_ZONE,
66
67
  "input_sources": INPUT_SOURCES_FOR_1_ZONE_DEVICE,
67
68
  "analog_output_sources": ANALOG_OUTPUT_SOURCES_FOR_1_ZONE_DEVICE,
68
- "features": [Features.BLUETOOTH],
69
+ "features": [Features.BLUETOOTH, Features.SUBWOOFER_CROSSOVER],
69
70
  }
70
71
  )
71
72
  A3 = Model(
@@ -92,7 +93,7 @@ class Models(VsslEnum):
92
93
  "zones": SINGLE_ZONE,
93
94
  "input_sources": INPUT_SOURCES_FOR_1_ZONE_DEVICE,
94
95
  "analog_output_sources": ANALOG_OUTPUT_SOURCES_FOR_1_ZONE_DEVICE,
95
- "features": [Features.GROUPING, Features.BLUETOOTH],
96
+ "features": [Features.BLUETOOTH, Features.SUBWOOFER_CROSSOVER],
96
97
  }
97
98
  )
98
99
  A3X = Model(
@@ -49,8 +49,8 @@ class InputRouter(ZoneDataClass):
49
49
  def __init__(self, zone: "zone.Zone"):
50
50
  self.zone = zone
51
51
 
52
- self._priority = self.Priorities.STREAM
53
- self._source = self.Sources.STREAM
52
+ self._priority = self.DEFAULTS["priority"]
53
+ self._source = self.DEFAULTS["source"]
54
54
 
55
55
  #
56
56
  # Input Priority
@@ -138,7 +138,7 @@ class AnalogOutput(ZoneDataClass):
138
138
  def __init__(self, zone: "zone.Zone"):
139
139
  self.zone = zone
140
140
 
141
- self._is_fixed_volume = False
141
+ self._is_fixed_volume = self.DEFAULTS["is_fixed_volume"]
142
142
  self._source = self.Sources(zone.id + 2)
143
143
 
144
144
  #
@@ -199,7 +199,7 @@ class AnalogInput(ZoneDataClass):
199
199
  self.zone = zone
200
200
 
201
201
  self._name = f"Analog In {self.zone.id}"
202
- self._fixed_gain = 0
202
+ self._fixed_gain = self.DEFAULTS["fixed_gain"]
203
203
 
204
204
  #
205
205
  # Analog Input Name
@@ -2,6 +2,7 @@ import logging
2
2
  from typing import Dict, Union
3
3
  from .utils import clamp_volume
4
4
  from .io import AnalogInput
5
+ from .device import Features as DeviceFeatures
5
6
  from .data_structure import (
6
7
  VsslIntEnum,
7
8
  VsslDataClass,
@@ -16,6 +17,7 @@ class VsslSettings(VsslDataClass):
16
17
  class Keys:
17
18
  NAME = "name"
18
19
  OPTICAL_INPUT_NAME = "optical_input_name"
20
+ BLUETOOTH = "bluetooth"
19
21
 
20
22
  #
21
23
  # VSSL Events
@@ -24,17 +26,23 @@ class VsslSettings(VsslDataClass):
24
26
  PREFIX = VSSL_SETTINGS_EVENT_PREFIX
25
27
  NAME_CHANGE = PREFIX + "name_changed"
26
28
  OPTICAL_INPUT_NAME_CHANGE = PREFIX + "optical_input_name_changed"
29
+ BLUETOOTH_CHANGE = PREFIX + "bluetooth_changed"
27
30
 
28
31
  #
29
32
  # Defaults
30
33
  #
31
- DEFAULTS = {Keys.NAME: None, Keys.OPTICAL_INPUT_NAME: "Optical In"}
34
+ DEFAULTS = {
35
+ Keys.NAME: None,
36
+ Keys.OPTICAL_INPUT_NAME: "Optical In",
37
+ Keys.BLUETOOTH: 0,
38
+ }
32
39
 
33
40
  def __init__(self, vssl: "vsslctrl.Vssl"):
34
41
  self._vssl = vssl
35
42
 
36
43
  self._name = None # device name
37
44
  self._optical_input_name = self.DEFAULTS[self.Keys.OPTICAL_INPUT_NAME]
45
+ self._bluetooth = self.DEFAULTS[self.Keys.BLUETOOTH]
38
46
  self.power = VsslPowerSettings(vssl)
39
47
 
40
48
  #
@@ -63,6 +71,30 @@ class VsslSettings(VsslDataClass):
63
71
  if zone:
64
72
  zone.api_alpha.request_action_15_12(name)
65
73
 
74
+ #
75
+ # Bluetooth
76
+ #
77
+ @property
78
+ def bluetooth(self):
79
+ return bool(self._bluetooth)
80
+
81
+ @bluetooth.setter
82
+ def bluetooth(self, enabled: bool):
83
+ if not self._vssl.model.supports_feature(DeviceFeatures.BLUETOOTH):
84
+ self._vssl._log_error(
85
+ f"VSSL {self._vssl.model.name} does not support Bluetooth"
86
+ )
87
+ return
88
+
89
+ zone = self._vssl.get_connected_zone()
90
+ if zone:
91
+ # TODO
92
+ # zone.api_alpha.request_action_bluetooth(not not enabled)
93
+ pass
94
+
95
+ def bluetooth_toggle(self):
96
+ self.bluetooth = False if self.bluetooth else True
97
+
66
98
 
67
99
  class VsslPowerSettings(VsslDataClass):
68
100
  #
@@ -165,6 +197,7 @@ class ZoneSettings(ZoneDataClass):
165
197
  self._mono = self.StereoMono.Stereo
166
198
 
167
199
  self.eq = EQSettings(zone)
200
+ self.subwoofer = SubwooferSettings(zone)
168
201
  self.volume = VolumeSettings(zone)
169
202
  self.analog_input = AnalogInput(zone)
170
203
 
@@ -653,3 +686,59 @@ class EQSettings(ZoneDataClass):
653
686
  @khz15_db.setter
654
687
  def khz15_db(self, val: int):
655
688
  self._set_frequency_on_device_db(self.Freqs.KHZ15, val)
689
+
690
+
691
+ # Not in io.py to prevent circ import in device.py
692
+ class SubwooferSettings(ZoneDataClass):
693
+ MIN_VALUE = 0
694
+ MAX_VALUE = 1000
695
+
696
+ #
697
+ # Subwoofer events
698
+ #
699
+ class Events:
700
+ PREFIX = "zone.subwoofer."
701
+ CROSSOVER_CHANGE = PREFIX + "crossover_change"
702
+
703
+ #
704
+ # Defaults
705
+ #
706
+ DEFAULTS = {"crossover": 0}
707
+
708
+ def __init__(self, zone: "zone.Zone"):
709
+ self.zone = zone
710
+
711
+ self._crossover = self.DEFAULTS["crossover"]
712
+
713
+ #
714
+ # Clamp between min and max
715
+ #
716
+ def _clamp_crossover(self, value: int = 100):
717
+ return int(max(self.MIN_VALUE, min(value, self.MAX_VALUE)))
718
+
719
+ #
720
+ # Crossover freq
721
+ #
722
+ @property
723
+ def crossover(self):
724
+ return self._crossover
725
+
726
+ @crossover.setter
727
+ def crossover(self, freq: int):
728
+ if not self.zone.vssl.model.supports_feature(
729
+ DeviceFeatures.SUBWOOFER_CROSSOVER
730
+ ):
731
+ self.zone._log_error(
732
+ f"VSSL {self.zone.vssl.model.name} does not have a subwoofer output"
733
+ )
734
+ return
735
+ #
736
+ # TODO
737
+ #
738
+ # self.zone.api_alpha.request_action_crossover(freq)
739
+
740
+ def _set_crossover(self, freq: int):
741
+ freq = self._clamp_crossover(freq)
742
+ if self.crossover != freq:
743
+ self._crossover = freq
744
+ return True
@@ -38,6 +38,19 @@ def group_list_by_property(input_list, property_key):
38
38
  return grouped_dict
39
39
 
40
40
 
41
+ #
42
+ # Logging Helper to show a command in bytearray([]) syntax
43
+ #
44
+ def hex_to_bytearray_string(hex_string):
45
+ # Convert the hex string to a bytearray
46
+ byte_array = bytearray.fromhex(hex_string)
47
+
48
+ # Create the bytearray string representation
49
+ bytearray_str = f'bytearray([{", ".join(map(str, byte_array))}])'
50
+
51
+ return bytearray_str
52
+
53
+
41
54
  #
42
55
  # Repeat Timer
43
56
  #
@@ -74,7 +74,7 @@ class Zone:
74
74
  self._request_eq_status,
75
75
  self._request_track,
76
76
  self._request_name,
77
- self._request_bt_status,
77
+ self._request_status_extended,
78
78
  ],
79
79
  )
80
80
 
@@ -128,6 +128,8 @@ class Zone:
128
128
  self.initialisation.set()
129
129
  self.vssl.event_bus.publish(self.Events.INITIALISED, self.id, self)
130
130
 
131
+ self._log_info(f"Zone {self.id} initialised")
132
+
131
133
  return self
132
134
 
133
135
  @property
@@ -267,6 +269,11 @@ class Zone:
267
269
  def _set_mac_addr(self, mac: str):
268
270
  mac = mac.strip()
269
271
  if mac != self.mac_addr:
272
+ # Strip Wlan0: from beginging of string
273
+ # Original A series amps had this prefix
274
+ if mac.startswith("Wlan0:"):
275
+ mac = mac[len("Wlan0:") :]
276
+
270
277
  # Define the regular expression pattern for a MAC address
271
278
  mac_pattern = re.compile(r"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")
272
279
 
@@ -401,7 +408,7 @@ class Zone:
401
408
  self.api_alpha.request_action_00_0A()
402
409
  return self
403
410
 
404
- def _request_bt_status(self):
411
+ def _request_status_extended(self):
405
412
  self.api_alpha.request_action_00_0B()
406
413
  return self
407
414
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vsslctrl
3
- Version: 0.1.5.dev1
4
- Summary: Package for controlling VSSL amplifiers
3
+ Version: 0.1.7.dev1
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
7
7
  Classifier: Programming Language :: Python :: 3
@@ -20,31 +20,30 @@ Provides-Extra: optional
20
20
  Requires-Dist: zeroconf==0.132.2; extra == "optional"
21
21
 
22
22
  # vsslctrl
23
- Package for controlling [VSSL](https://www.vssl.com/) range of streaming amplifiers.
23
+
24
+ Package for controlling [VSSL's](https://www.vssl.com/) range of streaming amplifiers.
24
25
 
25
26
  **`vsslctrl` is not endorsed or affiliated with [VSSL](https://www.vssl.com/) in any manner.**
26
27
 
27
- Motovation for this project was to intergrate VSSLs amplifiers into [Home Assistant](https://www.home-assistant.io/) and have control over different subnets (not mDNS dependant)
28
+ ## Help
28
29
 
29
- I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping.
30
+ I am looking for testers with any VSSL amplifier models, please get in touch if you interested in helping. <vsslcontrolled@proton.me>
30
31
 
31
- Important
32
- -----------
33
- Only tested on a VSSL **A.3x** software version **p15305.016.3701**.
32
+ Tested on:
33
+ - Test suite run on a VSSL **A.3x** software version **p15305.016.3701**
34
+ - The Home Assistant [integration](https://github.com/vsslctrl/integration.home-assistant) is reported working on a **A.6x** software version **p15305.017.3701**
34
35
 
35
- **Notice:** VSSLs new iOS app titled `VSSL`can cause connection refused issues if running at the same time as `vsslctrl`. Best to not use the iOS app togeather. The `VSSL Legacy` app works fine
36
+ ## Important
36
37
 
37
- **Warning:** no *[VSSL Agent](https://vssl.gitbook.io/vssl-rest-api/getting-started/start)* should be running on the same network. If you dont know what this is, then you can probably ignore this notice.
38
+ 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.
38
39
 
39
40
  ## TODOs
40
41
 
41
- * Test on other models (hardware needed)
42
- * Home Assistant integration. In progress, [here](https://github.com/vsslctrl/integration.home-assistant)
43
- * ~~Function scoping to supported feature / models~~ (needs tests)
42
+ * **A1(.x)** specific control e.g sub crossover, bluetooth
44
43
  * Better test coverage
45
44
 
46
- Basic Usage
47
- -----------
45
+ ## Basic Usage
46
+
48
47
  `vsslctrl` needs to be running inside a **[asyncio](https://docs.python.org/3/library/asyncio.html)** event loop.
49
48
 
50
49
  ```python
@@ -91,8 +90,7 @@ async def main():
91
90
  asyncio.run(main())
92
91
  ```
93
92
 
94
- API
95
- -----------
93
+ # API
96
94
 
97
95
  Most functionality is achived via `getters` and `setters` of the two main classes `Vssl`, `Zone`.
98
96
 
@@ -284,10 +282,10 @@ zone1.group.dissolve()
284
282
 
285
283
  ## `Zone.analog_output`
286
284
 
287
- | Property | Description | Type | Values |
288
- | ---------------------- | ----------- | ----------- |----------- |
289
- | `source` | Where the AO is routed from. i.e a zone, optical input or off | `int` | `AnalogOutput.Sources`
290
- | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` readonly
285
+ | Property | Description | Type | Values | Default |
286
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
287
+ | `source` | Where the AO is routed from. i.e a zone, optical input or off | `int` | `AnalogOutput.Sources` | `Off`
288
+ | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` | |`False`
291
289
  | `is_fixed_volume_toggle()` | Toggle fixed volume | `func` |
292
290
 
293
291
  ```python
@@ -304,12 +302,12 @@ zone1.analog_output.is_fixed_volume = True
304
302
 
305
303
  ## `Zone.settings`
306
304
 
307
- | Property | Description | Type | Values |
308
- | ---------------------- | ----------- | ----------- |----------- |
305
+ | Property | Description | Type | Values | Default |
306
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
309
307
  | `name` | Name | `str` |
310
- | `disabled` | Disable the zone | `bool`
308
+ | `disabled` | Disable the zone | `bool` || `False`
311
309
  | `disabled_toggle()` | disable / enable | `func` |
312
- | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono`
310
+ | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono` | `Stereo`
313
311
  | `mono_toggle()` | Toggle mono or stereo | `func` |
314
312
 
315
313
  ```python
@@ -324,10 +322,10 @@ zone1.mono_toggle()
324
322
 
325
323
  ## `Zone.settings.analog_input`
326
324
 
327
- | Property | Description | Type | Values |
328
- | ---------------------- | ----------- | ----------- |----------- |
325
+ | Property | Description | Type | Values | Default |
326
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
329
327
  | `name` | Name | `str` |
330
- | `fixed_gain` | Fix the input gain to a specific value |`int` | `0...100`
328
+ | `fixed_gain` | Fix the input gain to a specific value |`int` | `0...100` | `0` is disabled or variable gain
331
329
 
332
330
  ```python
333
331
  """Examples"""
@@ -341,11 +339,11 @@ zone1.settings.analog_input.fixed_gain = 50
341
339
 
342
340
  ## `Zone.settings.volume`
343
341
 
344
- | Property | Description | Type | Values |
345
- | ---------------------- | ----------- | ----------- |----------- |
346
- | `default_on` | Default on volume | `int` | `0...100`
347
- | `max_left` | Max volume left channel | `int` | `0...100`
348
- | `max_right` | Max volume right channel | `int` | `0...100`
342
+ | Property | Description | Type | Values | Default |
343
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
344
+ | `default_on` | Default on volume | `int` | `0...100` | `0` is disabled
345
+ | `max_left` | Max volume left channel | `int` | `0...100` | `75`
346
+ | `max_right` | Max volume right channel | `int` | `0...100` | `75`
349
347
 
350
348
  ```python
351
349
  """Examples"""
@@ -357,21 +355,21 @@ zone1.settings.volume.default_on = 75
357
355
 
358
356
  ## `Zone.settings.eq`
359
357
 
360
- | Property | Description | Type | Values |
361
- | ---------------------- | ----------- | ----------- |----------- |
362
- | `enabled` | Enable / disable EQ | `bool`
358
+ | Property | Description | Type | Values | Default |
359
+ | ---------------------- | ----------- | ----------- |----------- |----------- |
360
+ | `enabled` | Enable / disable EQ | `bool` | | `False`
363
361
 
364
362
  EQ to be set in [decibel](https://en.wikipedia.org/wiki/Decibel) using a range `-10`dB to `+10`dB
365
363
 
366
- | Property | Description | Type | Values |
367
- | ---------------------- | ----------- | ----------- |----------- |
368
- | `hz60_db` | 60Hz | `int` | `-10...10`
369
- | `hz200_db` | 200Hz | `int` | `-10...10`
370
- | `hz500_db` | 500Hz | `int` | `-10...10`
371
- | `khz1_db` | 1kHz | `int` | `-10...10`
372
- | `khz4_db` | 4kHz | `int` | `-10...10`
373
- | `khz8_db` | 8kHz | `int` | `-10...10`
374
- | `khz15_db` | 15kHz | `int` | `-10...10`
364
+ | Property | Description | Type | Values | Default |
365
+ | ---------------------- | ----------- | ----------- |----------- | ----------- |
366
+ | `hz60_db` | 60Hz | `int` | `-10...10` | `0`
367
+ | `hz200_db` | 200Hz | `int` | `-10...10` | `0`
368
+ | `hz500_db` | 500Hz | `int` | `-10...10` | `0`
369
+ | `khz1_db` | 1kHz | `int` | `-10...10` | `0`
370
+ | `khz4_db` | 4kHz | `int` | `-10...10` | `0`
371
+ | `khz8_db` | 8kHz | `int` | `-10...10` | `0`
372
+ | `khz15_db` | 15kHz | `int` | `-10...10` | `0`
375
373
 
376
374
  ```python
377
375
  """Examples"""
@@ -430,10 +428,11 @@ shell_command:
430
428
 
431
429
  The VSSL API was reverse engineered using Wireshark, VSSLs native "legacy" iOS app and their deprecated [vsslagent](https://vssl.gitbook.io/vssl-rest-api/getting-started/start).
432
430
 
431
+ Motovation for this project was to intergrate VSSLs amplifiers into [Home Assistant](https://www.home-assistant.io/) and have control over different subnets (not mDNS dependant)
432
+
433
433
  ## Known Issues & Limitiations
434
434
 
435
- * Tested on VSSL **A.3x** software version **p15305.016.3701**
436
- * Not tested on A.1x, A.6.x or original A series range of amplifiers (testers welcome)
435
+ * Not tested on A.1x or original A series range of amplifiers (testers welcome)
437
436
  * VSSL can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
438
437
  * Not all sources set the volume to 0 when the zone is muted
439
438
  * Grouping feedback is flaky on the X series amplifiers
@@ -445,8 +444,8 @@ The VSSL API was reverse engineered using Wireshark, VSSLs native "legacy" iOS a
445
444
 
446
445
  ## Future
447
446
 
447
+ * A.1(x) coverage i.e Bluetooth and subwoofer control
448
448
  * REST API / Web App
449
449
  * Save and recall EQ
450
- * A.1(x) coverage i.e Bluetooth
451
450
  * IR Control
452
451
 
File without changes
File without changes