vsslctrl 0.2.0__tar.gz → 0.2.1__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 (34) hide show
  1. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/PKG-INFO +42 -26
  2. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/README.md +41 -25
  3. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/pyproject.toml +1 -1
  4. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/__init__.py +1 -1
  5. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/event_bus.py +20 -2
  6. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/settings.py +9 -1
  7. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl.egg-info/PKG-INFO +42 -26
  8. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/LICENSE +0 -0
  9. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/setup.cfg +0 -0
  10. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/tests/test_api.py +0 -0
  11. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/tests/test_device.py +0 -0
  12. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/tests/test_event_bus.py +0 -0
  13. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/tests/test_integration.py +0 -0
  14. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/tests/test_settings.py +0 -0
  15. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/tests/test_zone.py +0 -0
  16. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/api_alpha.py +0 -0
  17. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/api_base.py +0 -0
  18. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/api_bravo.py +0 -0
  19. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/core.py +0 -0
  20. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/data_structure.py +0 -0
  21. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/decorators.py +0 -0
  22. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/device.py +0 -0
  23. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/discovery.py +0 -0
  24. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/exceptions.py +0 -0
  25. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/group.py +0 -0
  26. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/io.py +0 -0
  27. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/track.py +0 -0
  28. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/transport.py +0 -0
  29. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/utils.py +0 -0
  30. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl/zone.py +0 -0
  31. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl.egg-info/SOURCES.txt +0 -0
  32. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl.egg-info/dependency_links.txt +0 -0
  33. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl.egg-info/requires.txt +0 -0
  34. {vsslctrl-0.2.0 → vsslctrl-0.2.1}/vsslctrl.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vsslctrl
3
- Version: 0.2.0
3
+ Version: 0.2.1
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
@@ -188,7 +188,7 @@ print(zone1.settings.name)
188
188
  ```python
189
189
  from vsslctrl.settings import ZoneSettings
190
190
  # Setting the zone name and wait for feedback
191
- future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.id)
191
+ future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.host)
192
192
  zone1.settings.name = 'Bathroom'
193
193
  # Helper to await a future with timeout
194
194
  new_name = await vssl.event_bus.wait_future(future_name)
@@ -230,8 +230,7 @@ vssl.factory_reset()
230
230
  | `name` | Device name | `str` |
231
231
  | `bus_1_name` | Name of Bus 1 | `str` | <ul><li>`A.1`: Optical Input</li><li>`A.3x`/`A.6x`: Not Used</li></ul>
232
232
  | `bus_2_name` | Name of Bus 2 | `str` | <ul><li>`A.1`: Coax Input</li><li>`A.3x`/`A.6x`: Optical Input</li></ul>
233
- | `bluetooth` | Bluetooth enabled / disabled | `bool` |
234
- | `bluetooth_toggle()` | Toggle Bluetooth | `func` |
233
+ | `status_light_mode` | Status lights - Normal or Dark Mode | `str` | [`VsslSettings.StatusLightModes`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L17)
235
234
 
236
235
  ```python
237
236
  """Example"""
@@ -239,17 +238,35 @@ vssl.factory_reset()
239
238
  vssl.settings.name = 'My House'
240
239
  # Setting bus 2 name
241
240
  vssl.settings.bus_2_name = 'Optical Input'
241
+ ```
242
+
243
+ ## `Vssl.settings.bluetooth`
244
+
245
+ `A.1(x)` only.
246
+
247
+ | Property | Description | Type | Values |
248
+ | ---------------------- | ----------- | ----------- |----------- |
249
+ | `state` | Bluetooth state | `int` readonly | [`BluetoothSettings.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L130)
250
+ | `on()` | Enable Bluetooth | `func`
251
+ | `off()` | Disable Bluetooth | `func`
252
+ | `clear_pairs()` | Clear pairings | `func`
253
+ | `enter_pairing()` | Enter pairing | `func`
254
+ | `exit_pairing()` | Exit pairing | `func`
255
+ | `toggle()` | Toggle Bluetooth | `func` |
256
+
257
+ ```python
258
+ """Example"""
242
259
  # Enable Bluetooth
243
- vssl.settings.bluetooth = True
260
+ vssl.settings.bluetooth.on()
244
261
  # Toggle Bluetooth
245
- vssl.settings.bluetooth_toggle()
262
+ vssl.settings.bluetooth.toggle()
246
263
  ```
247
264
 
248
265
  ## `Vssl.settings.power`
249
266
 
250
267
  | Property | Description | Type | Values |
251
268
  | ---------------------- | ----------- | ----------- |----------- |
252
- | `state` | Power state | `int` readonly | `VsslPowerSettings.States`
269
+ | `state` | Power state | `int` readonly | [`VsslPowerSettings.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L243)
253
270
  | `adaptive` | Power adaptive | `bool`
254
271
 
255
272
  ```python
@@ -263,7 +280,7 @@ vssl.settings.power.adaptive = True
263
280
 
264
281
  | Property | Description | Type | Values |
265
282
  | ---------------------- | ----------- | ----------- |----------- |
266
- | `id` | Zone number / ID | `int` readonly | `ZoneIDs`
283
+ | `id` | Zone number / ID | `int` readonly | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
267
284
  | `host` | IP address | `str` readonly
268
285
  | `volume` | Volume | `int` | `0...100`
269
286
  | `volume_raise([step=1])` | Raise volume by `step` | `func` | step: `int` `1...100`
@@ -276,8 +293,9 @@ vssl.settings.power.adaptive = True
276
293
  | `next()` | Next track | `func` |
277
294
  | `prev()` | Begining of track or previous track | `func` |
278
295
  | `reboot()` | Reboot zone | `func` |
279
- | `play_url([url], [all_zones])` | Play a URL | `func` | url: `str`, all_zones: `bool`
296
+ | `play_url([url], [all_zones], [volume])` | Play a URL | `func` | url: `str`<br/>all_zones: `bool`<br/>volume: `int` `1...100`
280
297
 
298
+ **Note:** `play_url()` is intended as a PA system. The zone will stop repsonding to commands (e.g transport, volume etc.) until the requested file has finished playing.
281
299
 
282
300
  ```python
283
301
  """Examples"""
@@ -293,19 +311,19 @@ zone1.mute_toggle()
293
311
  zone1.pause()
294
312
  # Next track
295
313
  zone1.next()
296
- # Play a URL on this zone1
297
- zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3')
298
- # Play a URL on all zones
314
+ # Play a URL on this zone1 at 15% volume
315
+ zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3', volume=15)
316
+ # Play a URL on all zones at current volume level
299
317
  zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3', True)
300
318
  ```
301
319
 
302
320
  ## `Zone.transport`
303
321
 
304
- A VSSL amplifier can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
322
+ A VSSL amplifier can not start a stream except for when using `zone.play_url()`. This is a limitation of the hardware itself.
305
323
 
306
324
  | Property | Description | Type | Values |
307
325
  | ---------------------- | ----------- | ----------- |----------- |
308
- | `state` | Transport state. i.e Play, Stop, Pause | `int` | `ZoneTransport.States`
326
+ | `state` | Transport state. i.e Play, Stop, Pause | `int` | [`ZoneTransport.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/transport.py#L9)
309
327
  | `play()` | Play | `func` |
310
328
  | `stop()` | Stop | `func` |
311
329
  | `pause()` | Pause | `func` |
@@ -314,7 +332,7 @@ A VSSL amplifier can not start a stream except for playing a URL directly. This
314
332
  | `is_playing` | Is the zone playing | `bool` readonly
315
333
  | `is_stopped` | Is the zone stopped | `bool` readonly
316
334
  | `is_pasued` | Is the zone pasued | `bool` readonly
317
- | `is_repeat` | Repeat state. i.e all, one, off | `int` readonly | `ZoneTransport.Repeat`
335
+ | `is_repeat` | Repeat state. i.e all, one, off | `int` readonly | [`ZoneTransport.Repeat`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/transport.py#L19)
318
336
  | `is_shuffle` | Is shuffle enabled | `bool` readonly
319
337
  | `has_next` | Is the next button enabled | `bool` readonly
320
338
  | `has_prev` | Is the prev button enabled | `bool` readonly
@@ -341,7 +359,7 @@ zone1.transport.state = ZoneTransport.States.PAUSE
341
359
  | `duration` | Length in miliseconds (ms) | `int` readonly |
342
360
  | `progress` | Current position in miliseconds (ms) | `int` readonly |
343
361
  | `cover_art_url` | URL to cover art | `str` readonly |
344
- | `source` | Track source e.g Spotify | `int` readonly | `TrackMetadata.Sources`
362
+ | `source` | Track source e.g Spotify | `int` readonly | [`TrackMetadata.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/track.py#L28)
345
363
  | `url` | URL of file or track | `str` readonly |
346
364
 
347
365
 
@@ -349,8 +367,8 @@ zone1.transport.state = ZoneTransport.States.PAUSE
349
367
 
350
368
  | Property | Description | Type | Values |
351
369
  | ---------------------- | ----------- | ----------- |----------- |
352
- | `source` | Change input source.<br/>Source to be played out the zones speakers | `int` | `InputRouter.Sources`
353
- | `priority` | Change input priority.<br/>Stream or local to have precedence | `int` | `InputRouter.Priorities`
370
+ | `source` | Change input source.<br/>Source to be played out the zones speakers | `int` | [`InputRouter.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L35)
371
+ | `priority` | Change input priority.<br/>Stream or local to have precedence | `int` | [`InputRouter.Priorities`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L23)
354
372
 
355
373
 
356
374
  ### `A.1(x)` Source Routing Order
@@ -380,14 +398,12 @@ zone1.input.priority = InputRouter.Priorities.LOCAL
380
398
 
381
399
  ## `Zone.group`
382
400
 
383
- Unsupported on X series amplifiers.
384
-
385
401
  | Property | Description | Type | Values |
386
402
  | ---------------------- | ----------- | ----------- |----------- |
387
- | `source` | Zone ID of group master / source | `int` readonly | `ZoneIDs`
403
+ | `source` | Zone ID of group master / source | `int` readonly | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
388
404
  | `is_master` | This zone is the group master | `bool` readonly
389
- | `add_member()` | Add zone to group / create group | `func` | `ZoneIDs`
390
- | `remove_member()` | Remove zone from group | `func` | `ZoneIDs`
405
+ | `add_member()` | Add zone to group / create group | `func` | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
406
+ | `remove_member()` | Remove zone from group | `func` | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
391
407
  | `dissolve()` | Dissolve group / remove all members | `func` |
392
408
  | `leave()` | Leave the group if a member | `func` |
393
409
  | `is_party_zone_member` | Member of Party Zone | `bool` |
@@ -411,7 +427,7 @@ zone1.group.is_party_zone_member_toggle()
411
427
 
412
428
  | Property | Description | Type | Values | Default |
413
429
  | ---------------------- | ----------- | ----------- |----------- |----------- |
414
- | `source` | Where the AO is routed from. i.e stream, optical input or off | `int` | `AnalogOutput.Sources` | `Off`
430
+ | `source` | Where the AO is routed from. i.e stream, optical input or off | `int` | [`AnalogOutput.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L150) | `Off`
415
431
  | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` | |`False`
416
432
  | `is_fixed_volume_toggle()` | Toggle fixed volume | `func` |
417
433
 
@@ -434,7 +450,7 @@ zone1.analog_output.is_fixed_volume = True
434
450
  | `name` | Name | `str` |
435
451
  | `disabled` | Disable the zone | `bool` || `False`
436
452
  | `disabled_toggle()` | disable / enable | `func` |
437
- | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono` | `STEREO`
453
+ | `mono` | Set output to mono or stereo | `int` | [`ZoneSettings.StereoMono`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L310) | `STEREO`
438
454
  | `mono_toggle()` | Toggle mono or stereo | `func` |
439
455
 
440
456
  ```python
@@ -506,7 +522,7 @@ zone1.settings.eq.khz1_db = -2
506
522
 
507
523
  ## `Zone.settings.subwoofer`
508
524
 
509
- * **A.1 and A.1x only**
525
+ * **`A.1` and `A.1x` only**
510
526
  * Set `0` for full frequency range
511
527
 
512
528
  | Property | Description | Type | Values | Default |
@@ -166,7 +166,7 @@ print(zone1.settings.name)
166
166
  ```python
167
167
  from vsslctrl.settings import ZoneSettings
168
168
  # Setting the zone name and wait for feedback
169
- future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.id)
169
+ future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.host)
170
170
  zone1.settings.name = 'Bathroom'
171
171
  # Helper to await a future with timeout
172
172
  new_name = await vssl.event_bus.wait_future(future_name)
@@ -208,8 +208,7 @@ vssl.factory_reset()
208
208
  | `name` | Device name | `str` |
209
209
  | `bus_1_name` | Name of Bus 1 | `str` | <ul><li>`A.1`: Optical Input</li><li>`A.3x`/`A.6x`: Not Used</li></ul>
210
210
  | `bus_2_name` | Name of Bus 2 | `str` | <ul><li>`A.1`: Coax Input</li><li>`A.3x`/`A.6x`: Optical Input</li></ul>
211
- | `bluetooth` | Bluetooth enabled / disabled | `bool` |
212
- | `bluetooth_toggle()` | Toggle Bluetooth | `func` |
211
+ | `status_light_mode` | Status lights - Normal or Dark Mode | `str` | [`VsslSettings.StatusLightModes`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L17)
213
212
 
214
213
  ```python
215
214
  """Example"""
@@ -217,17 +216,35 @@ vssl.factory_reset()
217
216
  vssl.settings.name = 'My House'
218
217
  # Setting bus 2 name
219
218
  vssl.settings.bus_2_name = 'Optical Input'
219
+ ```
220
+
221
+ ## `Vssl.settings.bluetooth`
222
+
223
+ `A.1(x)` only.
224
+
225
+ | Property | Description | Type | Values |
226
+ | ---------------------- | ----------- | ----------- |----------- |
227
+ | `state` | Bluetooth state | `int` readonly | [`BluetoothSettings.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L130)
228
+ | `on()` | Enable Bluetooth | `func`
229
+ | `off()` | Disable Bluetooth | `func`
230
+ | `clear_pairs()` | Clear pairings | `func`
231
+ | `enter_pairing()` | Enter pairing | `func`
232
+ | `exit_pairing()` | Exit pairing | `func`
233
+ | `toggle()` | Toggle Bluetooth | `func` |
234
+
235
+ ```python
236
+ """Example"""
220
237
  # Enable Bluetooth
221
- vssl.settings.bluetooth = True
238
+ vssl.settings.bluetooth.on()
222
239
  # Toggle Bluetooth
223
- vssl.settings.bluetooth_toggle()
240
+ vssl.settings.bluetooth.toggle()
224
241
  ```
225
242
 
226
243
  ## `Vssl.settings.power`
227
244
 
228
245
  | Property | Description | Type | Values |
229
246
  | ---------------------- | ----------- | ----------- |----------- |
230
- | `state` | Power state | `int` readonly | `VsslPowerSettings.States`
247
+ | `state` | Power state | `int` readonly | [`VsslPowerSettings.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L243)
231
248
  | `adaptive` | Power adaptive | `bool`
232
249
 
233
250
  ```python
@@ -241,7 +258,7 @@ vssl.settings.power.adaptive = True
241
258
 
242
259
  | Property | Description | Type | Values |
243
260
  | ---------------------- | ----------- | ----------- |----------- |
244
- | `id` | Zone number / ID | `int` readonly | `ZoneIDs`
261
+ | `id` | Zone number / ID | `int` readonly | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
245
262
  | `host` | IP address | `str` readonly
246
263
  | `volume` | Volume | `int` | `0...100`
247
264
  | `volume_raise([step=1])` | Raise volume by `step` | `func` | step: `int` `1...100`
@@ -254,8 +271,9 @@ vssl.settings.power.adaptive = True
254
271
  | `next()` | Next track | `func` |
255
272
  | `prev()` | Begining of track or previous track | `func` |
256
273
  | `reboot()` | Reboot zone | `func` |
257
- | `play_url([url], [all_zones])` | Play a URL | `func` | url: `str`, all_zones: `bool`
274
+ | `play_url([url], [all_zones], [volume])` | Play a URL | `func` | url: `str`<br/>all_zones: `bool`<br/>volume: `int` `1...100`
258
275
 
276
+ **Note:** `play_url()` is intended as a PA system. The zone will stop repsonding to commands (e.g transport, volume etc.) until the requested file has finished playing.
259
277
 
260
278
  ```python
261
279
  """Examples"""
@@ -271,19 +289,19 @@ zone1.mute_toggle()
271
289
  zone1.pause()
272
290
  # Next track
273
291
  zone1.next()
274
- # Play a URL on this zone1
275
- zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3')
276
- # Play a URL on all zones
292
+ # Play a URL on this zone1 at 15% volume
293
+ zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3', volume=15)
294
+ # Play a URL on all zones at current volume level
277
295
  zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3', True)
278
296
  ```
279
297
 
280
298
  ## `Zone.transport`
281
299
 
282
- A VSSL amplifier can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
300
+ A VSSL amplifier can not start a stream except for when using `zone.play_url()`. This is a limitation of the hardware itself.
283
301
 
284
302
  | Property | Description | Type | Values |
285
303
  | ---------------------- | ----------- | ----------- |----------- |
286
- | `state` | Transport state. i.e Play, Stop, Pause | `int` | `ZoneTransport.States`
304
+ | `state` | Transport state. i.e Play, Stop, Pause | `int` | [`ZoneTransport.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/transport.py#L9)
287
305
  | `play()` | Play | `func` |
288
306
  | `stop()` | Stop | `func` |
289
307
  | `pause()` | Pause | `func` |
@@ -292,7 +310,7 @@ A VSSL amplifier can not start a stream except for playing a URL directly. This
292
310
  | `is_playing` | Is the zone playing | `bool` readonly
293
311
  | `is_stopped` | Is the zone stopped | `bool` readonly
294
312
  | `is_pasued` | Is the zone pasued | `bool` readonly
295
- | `is_repeat` | Repeat state. i.e all, one, off | `int` readonly | `ZoneTransport.Repeat`
313
+ | `is_repeat` | Repeat state. i.e all, one, off | `int` readonly | [`ZoneTransport.Repeat`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/transport.py#L19)
296
314
  | `is_shuffle` | Is shuffle enabled | `bool` readonly
297
315
  | `has_next` | Is the next button enabled | `bool` readonly
298
316
  | `has_prev` | Is the prev button enabled | `bool` readonly
@@ -319,7 +337,7 @@ zone1.transport.state = ZoneTransport.States.PAUSE
319
337
  | `duration` | Length in miliseconds (ms) | `int` readonly |
320
338
  | `progress` | Current position in miliseconds (ms) | `int` readonly |
321
339
  | `cover_art_url` | URL to cover art | `str` readonly |
322
- | `source` | Track source e.g Spotify | `int` readonly | `TrackMetadata.Sources`
340
+ | `source` | Track source e.g Spotify | `int` readonly | [`TrackMetadata.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/track.py#L28)
323
341
  | `url` | URL of file or track | `str` readonly |
324
342
 
325
343
 
@@ -327,8 +345,8 @@ zone1.transport.state = ZoneTransport.States.PAUSE
327
345
 
328
346
  | Property | Description | Type | Values |
329
347
  | ---------------------- | ----------- | ----------- |----------- |
330
- | `source` | Change input source.<br/>Source to be played out the zones speakers | `int` | `InputRouter.Sources`
331
- | `priority` | Change input priority.<br/>Stream or local to have precedence | `int` | `InputRouter.Priorities`
348
+ | `source` | Change input source.<br/>Source to be played out the zones speakers | `int` | [`InputRouter.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L35)
349
+ | `priority` | Change input priority.<br/>Stream or local to have precedence | `int` | [`InputRouter.Priorities`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L23)
332
350
 
333
351
 
334
352
  ### `A.1(x)` Source Routing Order
@@ -358,14 +376,12 @@ zone1.input.priority = InputRouter.Priorities.LOCAL
358
376
 
359
377
  ## `Zone.group`
360
378
 
361
- Unsupported on X series amplifiers.
362
-
363
379
  | Property | Description | Type | Values |
364
380
  | ---------------------- | ----------- | ----------- |----------- |
365
- | `source` | Zone ID of group master / source | `int` readonly | `ZoneIDs`
381
+ | `source` | Zone ID of group master / source | `int` readonly | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
366
382
  | `is_master` | This zone is the group master | `bool` readonly
367
- | `add_member()` | Add zone to group / create group | `func` | `ZoneIDs`
368
- | `remove_member()` | Remove zone from group | `func` | `ZoneIDs`
383
+ | `add_member()` | Add zone to group / create group | `func` | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
384
+ | `remove_member()` | Remove zone from group | `func` | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
369
385
  | `dissolve()` | Dissolve group / remove all members | `func` |
370
386
  | `leave()` | Leave the group if a member | `func` |
371
387
  | `is_party_zone_member` | Member of Party Zone | `bool` |
@@ -389,7 +405,7 @@ zone1.group.is_party_zone_member_toggle()
389
405
 
390
406
  | Property | Description | Type | Values | Default |
391
407
  | ---------------------- | ----------- | ----------- |----------- |----------- |
392
- | `source` | Where the AO is routed from. i.e stream, optical input or off | `int` | `AnalogOutput.Sources` | `Off`
408
+ | `source` | Where the AO is routed from. i.e stream, optical input or off | `int` | [`AnalogOutput.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L150) | `Off`
393
409
  | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` | |`False`
394
410
  | `is_fixed_volume_toggle()` | Toggle fixed volume | `func` |
395
411
 
@@ -412,7 +428,7 @@ zone1.analog_output.is_fixed_volume = True
412
428
  | `name` | Name | `str` |
413
429
  | `disabled` | Disable the zone | `bool` || `False`
414
430
  | `disabled_toggle()` | disable / enable | `func` |
415
- | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono` | `STEREO`
431
+ | `mono` | Set output to mono or stereo | `int` | [`ZoneSettings.StereoMono`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L310) | `STEREO`
416
432
  | `mono_toggle()` | Toggle mono or stereo | `func` |
417
433
 
418
434
  ```python
@@ -484,7 +500,7 @@ zone1.settings.eq.khz1_db = -2
484
500
 
485
501
  ## `Zone.settings.subwoofer`
486
502
 
487
- * **A.1 and A.1x only**
503
+ * **`A.1` and `A.1x` only**
488
504
  * Set `0` for full frequency range
489
505
 
490
506
  | Property | Description | Type | Values | Default |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vsslctrl"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Package for controlling VSSL's range of streaming amplifiers"
9
9
  authors = [
10
10
  { name="vsslctrl", email="vsslcontrolled@proton.me" },
@@ -1,4 +1,4 @@
1
- VSSL_VERSION = "0.2.0"
1
+ VSSL_VERSION = "0.2.1"
2
2
  VSSL_NAME = "VSSL"
3
3
 
4
4
  LOG_DIVIDER = "------------------------------------------------------"
@@ -18,19 +18,35 @@ class EventBus:
18
18
  self.event_queue = asyncio.Queue()
19
19
 
20
20
  self.running = False
21
+ self.process = None
21
22
 
22
- self.process = asyncio.create_task(self.process_events())
23
+ self.start()
23
24
 
24
25
  # Helper for wildcard matching, so we can use partial wildcards. e.g zone.api.connected
25
26
  def _matches_pattern(self, event_type, pattern):
26
27
  return fnmatch.fnmatch(event_type, pattern)
27
28
 
29
+ # Check we are actually processing
30
+ @property
31
+ def _is_alive(self):
32
+ return isinstance(self.process, asyncio.Task) and not self.process.done()
33
+
34
+ #
35
+ # Start
36
+ #
37
+ def start(self):
38
+ if self._is_alive:
39
+ return
40
+
41
+ self.process = asyncio.create_task(self.process_events())
42
+
28
43
  #
29
44
  # Stop
30
45
  #
31
46
  def stop(self):
32
47
  self.running = False
33
- self.process.cancel()
48
+ if isinstance(self.process, asyncio.Task):
49
+ self.process.cancel()
34
50
  self._log_debug(f"stopped event processing")
35
51
 
36
52
  #
@@ -115,6 +131,8 @@ class EventBus:
115
131
  # Publish Async (Use when inside events loop)
116
132
  #
117
133
  async def publish_async(self, event_type, entity=None, data=None):
134
+ # Start if we have been stopped
135
+ self.start()
118
136
  event_type = event_type.lower()
119
137
  await self.event_queue.put((event_type, entity, data))
120
138
 
@@ -523,6 +523,14 @@ class VolumeSettings(ZoneDataClass):
523
523
 
524
524
 
525
525
  class EQSettings(ZoneDataClass):
526
+ """
527
+ Simple EQ (as per VSSL apps):
528
+ Treble = 8khz + 15khz
529
+ Mid = 500hz + 1khz + 4khz
530
+ Bass = 60hz + 200hz
531
+
532
+ """
533
+
526
534
  MIN_VALUE = 90
527
535
  MAX_VALUE = 110
528
536
  MIN_VALUE_DB = -10
@@ -622,7 +630,7 @@ class EQSettings(ZoneDataClass):
622
630
  return int(max(self.MIN_VALUE, min(value, self.MAX_VALUE)))
623
631
 
624
632
  #
625
- # Map between -10 and +10
633
+ # Map between -10-+10 and 90-110
626
634
  #
627
635
  # 90 = -10db
628
636
  # 100 = 0db
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vsslctrl
3
- Version: 0.2.0
3
+ Version: 0.2.1
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
@@ -188,7 +188,7 @@ print(zone1.settings.name)
188
188
  ```python
189
189
  from vsslctrl.settings import ZoneSettings
190
190
  # Setting the zone name and wait for feedback
191
- future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.id)
191
+ future_name = vssl.event_bus.future(ZoneSettings.Events.NAME_CHANGE, zone1.host)
192
192
  zone1.settings.name = 'Bathroom'
193
193
  # Helper to await a future with timeout
194
194
  new_name = await vssl.event_bus.wait_future(future_name)
@@ -230,8 +230,7 @@ vssl.factory_reset()
230
230
  | `name` | Device name | `str` |
231
231
  | `bus_1_name` | Name of Bus 1 | `str` | <ul><li>`A.1`: Optical Input</li><li>`A.3x`/`A.6x`: Not Used</li></ul>
232
232
  | `bus_2_name` | Name of Bus 2 | `str` | <ul><li>`A.1`: Coax Input</li><li>`A.3x`/`A.6x`: Optical Input</li></ul>
233
- | `bluetooth` | Bluetooth enabled / disabled | `bool` |
234
- | `bluetooth_toggle()` | Toggle Bluetooth | `func` |
233
+ | `status_light_mode` | Status lights - Normal or Dark Mode | `str` | [`VsslSettings.StatusLightModes`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L17)
235
234
 
236
235
  ```python
237
236
  """Example"""
@@ -239,17 +238,35 @@ vssl.factory_reset()
239
238
  vssl.settings.name = 'My House'
240
239
  # Setting bus 2 name
241
240
  vssl.settings.bus_2_name = 'Optical Input'
241
+ ```
242
+
243
+ ## `Vssl.settings.bluetooth`
244
+
245
+ `A.1(x)` only.
246
+
247
+ | Property | Description | Type | Values |
248
+ | ---------------------- | ----------- | ----------- |----------- |
249
+ | `state` | Bluetooth state | `int` readonly | [`BluetoothSettings.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L130)
250
+ | `on()` | Enable Bluetooth | `func`
251
+ | `off()` | Disable Bluetooth | `func`
252
+ | `clear_pairs()` | Clear pairings | `func`
253
+ | `enter_pairing()` | Enter pairing | `func`
254
+ | `exit_pairing()` | Exit pairing | `func`
255
+ | `toggle()` | Toggle Bluetooth | `func` |
256
+
257
+ ```python
258
+ """Example"""
242
259
  # Enable Bluetooth
243
- vssl.settings.bluetooth = True
260
+ vssl.settings.bluetooth.on()
244
261
  # Toggle Bluetooth
245
- vssl.settings.bluetooth_toggle()
262
+ vssl.settings.bluetooth.toggle()
246
263
  ```
247
264
 
248
265
  ## `Vssl.settings.power`
249
266
 
250
267
  | Property | Description | Type | Values |
251
268
  | ---------------------- | ----------- | ----------- |----------- |
252
- | `state` | Power state | `int` readonly | `VsslPowerSettings.States`
269
+ | `state` | Power state | `int` readonly | [`VsslPowerSettings.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L243)
253
270
  | `adaptive` | Power adaptive | `bool`
254
271
 
255
272
  ```python
@@ -263,7 +280,7 @@ vssl.settings.power.adaptive = True
263
280
 
264
281
  | Property | Description | Type | Values |
265
282
  | ---------------------- | ----------- | ----------- |----------- |
266
- | `id` | Zone number / ID | `int` readonly | `ZoneIDs`
283
+ | `id` | Zone number / ID | `int` readonly | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
267
284
  | `host` | IP address | `str` readonly
268
285
  | `volume` | Volume | `int` | `0...100`
269
286
  | `volume_raise([step=1])` | Raise volume by `step` | `func` | step: `int` `1...100`
@@ -276,8 +293,9 @@ vssl.settings.power.adaptive = True
276
293
  | `next()` | Next track | `func` |
277
294
  | `prev()` | Begining of track or previous track | `func` |
278
295
  | `reboot()` | Reboot zone | `func` |
279
- | `play_url([url], [all_zones])` | Play a URL | `func` | url: `str`, all_zones: `bool`
296
+ | `play_url([url], [all_zones], [volume])` | Play a URL | `func` | url: `str`<br/>all_zones: `bool`<br/>volume: `int` `1...100`
280
297
 
298
+ **Note:** `play_url()` is intended as a PA system. The zone will stop repsonding to commands (e.g transport, volume etc.) until the requested file has finished playing.
281
299
 
282
300
  ```python
283
301
  """Examples"""
@@ -293,19 +311,19 @@ zone1.mute_toggle()
293
311
  zone1.pause()
294
312
  # Next track
295
313
  zone1.next()
296
- # Play a URL on this zone1
297
- zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3')
298
- # Play a URL on all zones
314
+ # Play a URL on this zone1 at 15% volume
315
+ zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3', volume=15)
316
+ # Play a URL on all zones at current volume level
299
317
  zone1.play_url('http://soundbible.com/grab.php?id=2217&type=mp3', True)
300
318
  ```
301
319
 
302
320
  ## `Zone.transport`
303
321
 
304
- A VSSL amplifier can not start a stream except for playing a URL directly. This is a limitation of the hardware itself.
322
+ A VSSL amplifier can not start a stream except for when using `zone.play_url()`. This is a limitation of the hardware itself.
305
323
 
306
324
  | Property | Description | Type | Values |
307
325
  | ---------------------- | ----------- | ----------- |----------- |
308
- | `state` | Transport state. i.e Play, Stop, Pause | `int` | `ZoneTransport.States`
326
+ | `state` | Transport state. i.e Play, Stop, Pause | `int` | [`ZoneTransport.States`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/transport.py#L9)
309
327
  | `play()` | Play | `func` |
310
328
  | `stop()` | Stop | `func` |
311
329
  | `pause()` | Pause | `func` |
@@ -314,7 +332,7 @@ A VSSL amplifier can not start a stream except for playing a URL directly. This
314
332
  | `is_playing` | Is the zone playing | `bool` readonly
315
333
  | `is_stopped` | Is the zone stopped | `bool` readonly
316
334
  | `is_pasued` | Is the zone pasued | `bool` readonly
317
- | `is_repeat` | Repeat state. i.e all, one, off | `int` readonly | `ZoneTransport.Repeat`
335
+ | `is_repeat` | Repeat state. i.e all, one, off | `int` readonly | [`ZoneTransport.Repeat`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/transport.py#L19)
318
336
  | `is_shuffle` | Is shuffle enabled | `bool` readonly
319
337
  | `has_next` | Is the next button enabled | `bool` readonly
320
338
  | `has_prev` | Is the prev button enabled | `bool` readonly
@@ -341,7 +359,7 @@ zone1.transport.state = ZoneTransport.States.PAUSE
341
359
  | `duration` | Length in miliseconds (ms) | `int` readonly |
342
360
  | `progress` | Current position in miliseconds (ms) | `int` readonly |
343
361
  | `cover_art_url` | URL to cover art | `str` readonly |
344
- | `source` | Track source e.g Spotify | `int` readonly | `TrackMetadata.Sources`
362
+ | `source` | Track source e.g Spotify | `int` readonly | [`TrackMetadata.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/track.py#L28)
345
363
  | `url` | URL of file or track | `str` readonly |
346
364
 
347
365
 
@@ -349,8 +367,8 @@ zone1.transport.state = ZoneTransport.States.PAUSE
349
367
 
350
368
  | Property | Description | Type | Values |
351
369
  | ---------------------- | ----------- | ----------- |----------- |
352
- | `source` | Change input source.<br/>Source to be played out the zones speakers | `int` | `InputRouter.Sources`
353
- | `priority` | Change input priority.<br/>Stream or local to have precedence | `int` | `InputRouter.Priorities`
370
+ | `source` | Change input source.<br/>Source to be played out the zones speakers | `int` | [`InputRouter.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L35)
371
+ | `priority` | Change input priority.<br/>Stream or local to have precedence | `int` | [`InputRouter.Priorities`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L23)
354
372
 
355
373
 
356
374
  ### `A.1(x)` Source Routing Order
@@ -380,14 +398,12 @@ zone1.input.priority = InputRouter.Priorities.LOCAL
380
398
 
381
399
  ## `Zone.group`
382
400
 
383
- Unsupported on X series amplifiers.
384
-
385
401
  | Property | Description | Type | Values |
386
402
  | ---------------------- | ----------- | ----------- |----------- |
387
- | `source` | Zone ID of group master / source | `int` readonly | `ZoneIDs`
403
+ | `source` | Zone ID of group master / source | `int` readonly | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
388
404
  | `is_master` | This zone is the group master | `bool` readonly
389
- | `add_member()` | Add zone to group / create group | `func` | `ZoneIDs`
390
- | `remove_member()` | Remove zone from group | `func` | `ZoneIDs`
405
+ | `add_member()` | Add zone to group / create group | `func` | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
406
+ | `remove_member()` | Remove zone from group | `func` | [`ZoneIDs`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/data_structure.py#L75)
391
407
  | `dissolve()` | Dissolve group / remove all members | `func` |
392
408
  | `leave()` | Leave the group if a member | `func` |
393
409
  | `is_party_zone_member` | Member of Party Zone | `bool` |
@@ -411,7 +427,7 @@ zone1.group.is_party_zone_member_toggle()
411
427
 
412
428
  | Property | Description | Type | Values | Default |
413
429
  | ---------------------- | ----------- | ----------- |----------- |----------- |
414
- | `source` | Where the AO is routed from. i.e stream, optical input or off | `int` | `AnalogOutput.Sources` | `Off`
430
+ | `source` | Where the AO is routed from. i.e stream, optical input or off | `int` | [`AnalogOutput.Sources`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/io.py#L150) | `Off`
415
431
  | `is_fixed_volume` | Fix the output volume. Output wont respond to volume control | `bool` | |`False`
416
432
  | `is_fixed_volume_toggle()` | Toggle fixed volume | `func` |
417
433
 
@@ -434,7 +450,7 @@ zone1.analog_output.is_fixed_volume = True
434
450
  | `name` | Name | `str` |
435
451
  | `disabled` | Disable the zone | `bool` || `False`
436
452
  | `disabled_toggle()` | disable / enable | `func` |
437
- | `mono` | Set output to mono or stereo | `int` | `ZoneSettings.StereoMono` | `STEREO`
453
+ | `mono` | Set output to mono or stereo | `int` | [`ZoneSettings.StereoMono`](https://github.com/vsslctrl/vsslctrl/blob/644586fa183def1f23f0bfd239454fa8422e3dbe/vsslctrl/settings.py#L310) | `STEREO`
438
454
  | `mono_toggle()` | Toggle mono or stereo | `func` |
439
455
 
440
456
  ```python
@@ -506,7 +522,7 @@ zone1.settings.eq.khz1_db = -2
506
522
 
507
523
  ## `Zone.settings.subwoofer`
508
524
 
509
- * **A.1 and A.1x only**
525
+ * **`A.1` and `A.1x` only**
510
526
  * Set `0` for full frequency range
511
527
 
512
528
  | Property | Description | Type | Values | Default |
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes