pybeoplay 2.3.0__tar.gz → 2.4.0__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.
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/PKG-INFO +2 -2
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay/__init__.py +93 -40
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay/const.py +10 -6
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay.egg-info/PKG-INFO +2 -2
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/setup.py +1 -1
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/LICENSE +0 -0
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/README.md +0 -0
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay.egg-info/SOURCES.txt +0 -0
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay.egg-info/dependency_links.txt +0 -0
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay.egg-info/not-zip-safe +0 -0
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/pybeoplay.egg-info/top_level.txt +0 -0
- {pybeoplay-2.3.0 → pybeoplay-2.4.0}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pybeoplay
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: BeoPlay API for Python
|
|
5
5
|
Home-page: https://github.com/giachello/pybeoplay
|
|
6
|
-
Download-URL: https://github.com/giachello/pybeoplay/tarball/2.
|
|
6
|
+
Download-URL: https://github.com/giachello/pybeoplay/tarball/2.4.0
|
|
7
7
|
Author: Giovanni Iachello
|
|
8
8
|
Author-email: giovanni.iachello@gmail.com
|
|
9
9
|
License: MIT License
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
BeoPlay JSON interface for Bang & Olufsen Speakers, TVs and other NL devices
|
|
4
|
+
Reference: https://documenter.getpostman.com/view/1053298/T1LTe4Lt#intro
|
|
5
|
+
Reference: https://raw.githubusercontent.com/PolyPv/BeoRemote/master/BeoRemote.txt
|
|
6
|
+
Lifted a lot of code from marton borzak's ha-beoplay
|
|
7
|
+
|
|
8
|
+
https://widdowquinn.github.io/coding/update-pypi-package/
|
|
9
|
+
|
|
10
|
+
"""
|
|
10
11
|
|
|
11
12
|
import requests
|
|
12
13
|
import aiohttp
|
|
@@ -25,7 +26,8 @@ class BeoPlay(object):
|
|
|
25
26
|
"""Initializes a BeoPlay connection to the speaker / TV
|
|
26
27
|
Host: the IP address of the speaker
|
|
27
28
|
Session (optional): a asyncio client session to be used for async
|
|
28
|
-
communication with the speaker (if not provided, only blocking calls
|
|
29
|
+
communication with the speaker (if not provided, only blocking calls
|
|
30
|
+
using Requests will work)
|
|
29
31
|
"""
|
|
30
32
|
# network information
|
|
31
33
|
self._host = host
|
|
@@ -34,6 +36,7 @@ class BeoPlay(object):
|
|
|
34
36
|
)
|
|
35
37
|
self._connfail = 0
|
|
36
38
|
self._clientsession = session
|
|
39
|
+
# The following are only going ot be valid after a call to getDeviceInfo
|
|
37
40
|
# device information
|
|
38
41
|
self._name = None
|
|
39
42
|
self._serialNumber = None
|
|
@@ -42,6 +45,10 @@ class BeoPlay(object):
|
|
|
42
45
|
self._typeName = None
|
|
43
46
|
self._softwareVersion = None
|
|
44
47
|
self._hardwareVersion = None
|
|
48
|
+
# The following are only going ot be valid after a call to getMediaInfo, getStandby
|
|
49
|
+
# Or, they are updated by the Notifications task. The actual field updated by
|
|
50
|
+
# Notifications varies by device. Some devices for example provide notifications when
|
|
51
|
+
# Sound mode changes (e.g., Stage), others (e.g., BeoVision Avant 55) don't.
|
|
45
52
|
# State and Media information
|
|
46
53
|
self.on = None
|
|
47
54
|
self.min_volume = None
|
|
@@ -57,14 +64,17 @@ class BeoPlay(object):
|
|
|
57
64
|
self.media_country = None
|
|
58
65
|
self.media_languages = None
|
|
59
66
|
self.primary_experience = None
|
|
67
|
+
# The following are only going ot be valid after a call to getSources
|
|
60
68
|
# Sources
|
|
61
69
|
self.source = None
|
|
62
70
|
self.sources = []
|
|
63
71
|
self.sourcesID = []
|
|
64
72
|
self.sourcesBorrowed = []
|
|
73
|
+
# The following are only going ot be valid after a call to getSoundModes
|
|
65
74
|
# Sound modes
|
|
66
|
-
self.
|
|
75
|
+
self._soundMode = None
|
|
67
76
|
self._soundModes = {}
|
|
77
|
+
# The following are only going ot be valid after a call to getStandPosition
|
|
68
78
|
# Stand control
|
|
69
79
|
self.standPosition = None
|
|
70
80
|
self.standPositions = []
|
|
@@ -120,6 +130,11 @@ class BeoPlay(object):
|
|
|
120
130
|
"""Get the list of available digits"""
|
|
121
131
|
return BEOPLAY_DIGITS
|
|
122
132
|
|
|
133
|
+
@property
|
|
134
|
+
def soundMode(self):
|
|
135
|
+
"""Get the current sound modes"""
|
|
136
|
+
return self._soundMode
|
|
137
|
+
|
|
123
138
|
@property
|
|
124
139
|
def soundModes(self):
|
|
125
140
|
"""Get the list of available sound modes"""
|
|
@@ -127,7 +142,7 @@ class BeoPlay(object):
|
|
|
127
142
|
|
|
128
143
|
@property
|
|
129
144
|
def soundModesID(self):
|
|
130
|
-
"""Get the list of available sound
|
|
145
|
+
"""Get the list of available sound mode IDs"""
|
|
131
146
|
return list(self._soundModes.values())
|
|
132
147
|
|
|
133
148
|
###############################################################
|
|
@@ -236,9 +251,16 @@ class BeoPlay(object):
|
|
|
236
251
|
# GET ATTRIBUTES FROM THE SPEAKER - NON-BLOCKING CALLS
|
|
237
252
|
###############################################################
|
|
238
253
|
|
|
254
|
+
async def async_get_source(self):
|
|
255
|
+
self.source = None
|
|
256
|
+
r = await self.async_getReq(BEOPLAY_URL_ACTIVE_SOURCES)
|
|
257
|
+
if r:
|
|
258
|
+
self.source = r["primaryExperience"]["source"]["friendlyName"] if "friendlyName" in r["primaryExperience"]["source"] else None
|
|
259
|
+
return self.source
|
|
260
|
+
|
|
239
261
|
# edited to only include in Use sources
|
|
240
262
|
async def async_get_sources(self):
|
|
241
|
-
r = await self.async_getReq(
|
|
263
|
+
r = await self.async_getReq(BEOPLAY_URL_GET_SOURCES)
|
|
242
264
|
if r:
|
|
243
265
|
# clear previously stored sources
|
|
244
266
|
self.sources = []
|
|
@@ -257,7 +279,7 @@ class BeoPlay(object):
|
|
|
257
279
|
|
|
258
280
|
async def async_get_standby(self) -> bool:
|
|
259
281
|
"""Returns True of the device is on, False if off."""
|
|
260
|
-
r = await self.async_getReq(
|
|
282
|
+
r = await self.async_getReq(BEOPLAY_URL_STANDBY)
|
|
261
283
|
if r:
|
|
262
284
|
if r["standby"]["powerState"] == "on":
|
|
263
285
|
self.on = True
|
|
@@ -267,25 +289,29 @@ class BeoPlay(object):
|
|
|
267
289
|
return
|
|
268
290
|
|
|
269
291
|
async def async_get_sound_mode(self):
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return
|
|
292
|
+
"""Returns the current sound mode, or None if not retrieved."""
|
|
293
|
+
self._soundMode = None
|
|
294
|
+
await self.async_get_sound_modes()
|
|
295
|
+
return self._soundMode
|
|
275
296
|
|
|
276
297
|
async def async_get_sound_modes(self):
|
|
298
|
+
"""Returns a dictionary of available sound modes, or None if not retrieved."""
|
|
277
299
|
r = await self.async_getReq(BEOPLAY_URL_GET_SOUND_MODE)
|
|
278
300
|
if r:
|
|
279
301
|
r = r.get("mode", {"list": []})
|
|
280
|
-
|
|
281
|
-
|
|
302
|
+
l = r.get("list", [])
|
|
303
|
+
a = r.get("active", None)
|
|
304
|
+
for element in l:
|
|
282
305
|
self._soundModes[element["friendlyName"]] = element["id"]
|
|
306
|
+
if a and a == element["id"]:
|
|
307
|
+
self._soundMode = element["friendlyName"]
|
|
283
308
|
return self._soundModes
|
|
284
309
|
return
|
|
285
310
|
|
|
286
311
|
async def async_get_stand_position(self):
|
|
287
312
|
"""Returns the stand position, or None if not retrieved."""
|
|
288
|
-
|
|
313
|
+
self._standPosition = None
|
|
314
|
+
r = await self.async_getReq(BEOPLAY_URL_STAND_ACTIVE)
|
|
289
315
|
if r:
|
|
290
316
|
if r["active"] is not None:
|
|
291
317
|
self._standPosition = r["active"]
|
|
@@ -293,11 +319,11 @@ class BeoPlay(object):
|
|
|
293
319
|
return
|
|
294
320
|
|
|
295
321
|
async def async_get_stand_positions(self):
|
|
296
|
-
|
|
322
|
+
# clear previous stand positions
|
|
323
|
+
self.standPositions = []
|
|
324
|
+
self.standPositionsID = []
|
|
325
|
+
r = await self.async_getReq(BEOPLAY_URL_STAND)
|
|
297
326
|
if r:
|
|
298
|
-
# clear previous stand positions
|
|
299
|
-
self.standPositions = []
|
|
300
|
-
self.standPositionsID = []
|
|
301
327
|
for elements in r:
|
|
302
328
|
i = 0
|
|
303
329
|
while i < len(r[elements]):
|
|
@@ -383,7 +409,7 @@ class BeoPlay(object):
|
|
|
383
409
|
chosenSource = self.sourcesID[i]
|
|
384
410
|
await self.async_postReq(
|
|
385
411
|
"POST",
|
|
386
|
-
|
|
412
|
+
BEOPLAY_URL_ACTIVE_SOURCES,
|
|
387
413
|
{"primaryExperience": {"source": {"id": chosenSource}}},
|
|
388
414
|
)
|
|
389
415
|
i += 1
|
|
@@ -407,7 +433,7 @@ class BeoPlay(object):
|
|
|
407
433
|
if self.standPositions[i] == standPosition:
|
|
408
434
|
chosenStandPosition = self.standPositionsID[i]
|
|
409
435
|
await self.async_postReq(
|
|
410
|
-
"PUT",
|
|
436
|
+
"PUT", BEOPLAY_URL_STAND_ACTIVE, {"active": chosenStandPosition}
|
|
411
437
|
)
|
|
412
438
|
i += 1
|
|
413
439
|
|
|
@@ -554,7 +580,7 @@ class BeoPlay(object):
|
|
|
554
580
|
|
|
555
581
|
# edited to only include in Use sources
|
|
556
582
|
def getSources(self):
|
|
557
|
-
r = self._getReq(
|
|
583
|
+
r = self._getReq(BEOPLAY_URL_GET_SOURCES)
|
|
558
584
|
if r:
|
|
559
585
|
for elements in r:
|
|
560
586
|
i = 0
|
|
@@ -565,8 +591,15 @@ class BeoPlay(object):
|
|
|
565
591
|
self.sourcesID.append(r[elements][i][0])
|
|
566
592
|
i += 1
|
|
567
593
|
|
|
594
|
+
def getSource(self):
|
|
595
|
+
self.source = None
|
|
596
|
+
r = self._getReq(BEOPLAY_URL_ACTIVE_SOURCES)
|
|
597
|
+
if r:
|
|
598
|
+
self.source = r["primaryExperience"]["source"]["friendlyName"] if "friendlyName" in r["primaryExperience"]["source"] else None
|
|
599
|
+
return self.source
|
|
600
|
+
|
|
568
601
|
def getStandby(self):
|
|
569
|
-
r = self._getReq(
|
|
602
|
+
r = self._getReq(BEOPLAY_URL_STANDBY)
|
|
570
603
|
if r:
|
|
571
604
|
if r["standby"]["powerState"] == "on":
|
|
572
605
|
self.on = True
|
|
@@ -574,26 +607,38 @@ class BeoPlay(object):
|
|
|
574
607
|
self.on = False
|
|
575
608
|
|
|
576
609
|
def getSoundMode(self):
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
610
|
+
""" Get sound mode. Return the current active sound mode or None if not retreived."""
|
|
611
|
+
self._soundMode = None
|
|
612
|
+
self.getSoundModes()
|
|
613
|
+
return self._soundMode
|
|
580
614
|
|
|
581
615
|
def getSoundModes(self):
|
|
616
|
+
""" Get sound modes. You need to call this before reading soundMode or soundModes."""
|
|
582
617
|
r = self._getReq(BEOPLAY_URL_GET_SOUND_MODE)
|
|
583
618
|
if r:
|
|
584
619
|
r = r.get("mode", {"list": []})
|
|
585
|
-
|
|
586
|
-
|
|
620
|
+
l = r.get("list", [])
|
|
621
|
+
a = r.get("active", None)
|
|
622
|
+
for element in l:
|
|
587
623
|
self._soundModes[element["friendlyName"]] = element["id"]
|
|
624
|
+
if a and a == element["id"]:
|
|
625
|
+
self._soundMode = element["friendlyName"]
|
|
626
|
+
return self._soundModes
|
|
627
|
+
return None
|
|
588
628
|
|
|
589
629
|
def getStandPosition(self):
|
|
590
|
-
|
|
630
|
+
self._standPosition = None
|
|
631
|
+
r = self._getReq(BEOPLAY_URL_STAND_ACTIVE)
|
|
591
632
|
if r:
|
|
592
633
|
if r["active"] is not None:
|
|
593
|
-
self._standPosition = r["active"]
|
|
634
|
+
self._standPosition = r["active"]
|
|
635
|
+
return self._standPosition
|
|
636
|
+
return None
|
|
594
637
|
|
|
595
638
|
def getStandPositions(self):
|
|
596
|
-
|
|
639
|
+
self.standPositions = []
|
|
640
|
+
self.standPositionsID = []
|
|
641
|
+
r = self._getReq(BEOPLAY_URL_STAND)
|
|
597
642
|
if r:
|
|
598
643
|
for elements in r:
|
|
599
644
|
i = 0
|
|
@@ -601,6 +646,7 @@ class BeoPlay(object):
|
|
|
601
646
|
self.standPositions.append(r[elements][i][1]["friendlyName"])
|
|
602
647
|
self.standPositionsID.append(r[elements][i][0])
|
|
603
648
|
i += 1
|
|
649
|
+
return self.standPositions
|
|
604
650
|
|
|
605
651
|
def getDeviceInfo(self):
|
|
606
652
|
r = self._getReq("BeoDevice")
|
|
@@ -674,7 +720,7 @@ class BeoPlay(object):
|
|
|
674
720
|
chosenSource = self.sourcesID[i]
|
|
675
721
|
self._postReq(
|
|
676
722
|
"POST",
|
|
677
|
-
|
|
723
|
+
BEOPLAY_URL_ACTIVE_SOURCES,
|
|
678
724
|
{"primaryExperience": {"source": {"id": chosenSource}}},
|
|
679
725
|
)
|
|
680
726
|
i += 1
|
|
@@ -697,7 +743,7 @@ class BeoPlay(object):
|
|
|
697
743
|
if self.standPositions[i] == standPosition:
|
|
698
744
|
chosenStandPosition = self.standPositionsID[i]
|
|
699
745
|
self._postReq(
|
|
700
|
-
"PUT",
|
|
746
|
+
"PUT", BEOPLAY_URL_STAND_ACTIVE, {"active": chosenStandPosition}
|
|
701
747
|
)
|
|
702
748
|
i += 1
|
|
703
749
|
|
|
@@ -854,6 +900,11 @@ class BeoPlay(object):
|
|
|
854
900
|
+ data["notification"]["data"]["name"]
|
|
855
901
|
)
|
|
856
902
|
|
|
903
|
+
def _processSoundMode(self, data):
|
|
904
|
+
if data["notification"]["type"] == "SOUND_ACTIVE_MODE_CHANGED":
|
|
905
|
+
self.soundMode = data["notification"]["data"]["friendlyName"]
|
|
906
|
+
|
|
907
|
+
|
|
857
908
|
def _processNotification(self, data):
|
|
858
909
|
"""Cumulative process all the potential notification information."""
|
|
859
910
|
try:
|
|
@@ -865,5 +916,7 @@ class BeoPlay(object):
|
|
|
865
916
|
self._processState(data)
|
|
866
917
|
# get currently playing music info
|
|
867
918
|
self._processMusicInfo(data)
|
|
919
|
+
# get sound mode
|
|
920
|
+
self._processSoundMode(data)
|
|
868
921
|
except KeyError:
|
|
869
922
|
LOG.debug("Malformed notification: %s", str(data))
|
|
@@ -5,16 +5,15 @@
|
|
|
5
5
|
# Lifted a lot of code from marton borzak's ha-beoplay
|
|
6
6
|
#
|
|
7
7
|
#
|
|
8
|
-
# pybeoplay constants
|
|
9
|
-
#
|
|
10
|
-
|
|
11
8
|
|
|
9
|
+
# Connection constants
|
|
12
10
|
BASE_URL = 'http://{0}:8080/{1}'
|
|
13
11
|
TIMEOUT = 5.0
|
|
14
12
|
CONNFAILCOUNT = 5
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
# BeoPlay constants
|
|
17
15
|
BEOPLAY_URL_NOTIFICATIONS = 'BeoNotify/Notifications'
|
|
16
|
+
|
|
18
17
|
BEOPLAY_URL_SET_VOLUME = 'BeoZone/Zone/Sound/Volume/Speaker/Level'
|
|
19
18
|
BEOPLAY_URL_MUTE = 'BeoZone/Zone/Sound/Volume/Speaker/Muted'
|
|
20
19
|
BEOPLAY_URL_PLAY = 'BeoZone/Zone/Stream/Play'
|
|
@@ -28,10 +27,15 @@ BEOPLAY_URL_STEPDOWN = 'BeoZone/Zone/List/StepDown'
|
|
|
28
27
|
BEOPLAY_URL_SHUFFLE = 'BeoZone/Zone/List/Shuffle'
|
|
29
28
|
BEOPLAY_URL_REPEAT = 'BeoZone/Zone/List/Repeat'
|
|
30
29
|
BEOPLAY_URL_STANDBY = 'BeoDevice/powerManagement/standby'
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
|
|
31
|
+
BEOPLAY_URL_GET_SOURCES = 'BeoZone/Zone/Sources'
|
|
32
|
+
BEOPLAY_URL_ACTIVE_SOURCES = 'BeoZone/Zone/ActiveSources'
|
|
33
|
+
|
|
34
|
+
BEOPLAY_URL_STAND_ACTIVE = 'BeoZone/Zone/Stand/Active'
|
|
35
|
+
BEOPLAY_URL_STAND = 'BeoZone/Zone/Stand'
|
|
33
36
|
BEOPLAY_URL_GET_SOUND_MODE = 'BeoZone/Zone/Sound/Mode'
|
|
34
37
|
BEOPLAY_URL_SET_SOUND_MODE = 'BeoZone/Zone/Sound/Mode/Active'
|
|
38
|
+
|
|
35
39
|
BEOPLAY_URL_JOIN_EXPERIENCE = 'BeoZone/Zone/Device/OneWayJoin'
|
|
36
40
|
BEOPLAY_URL_LEAVE_EXPERIENCE = 'BeoZone/Zone/ActiveSources/primaryExperience'
|
|
37
41
|
BEOPLAY_URL_PLAYQUEUE = 'BeoZone/Zone/PlayQueue'
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pybeoplay
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: BeoPlay API for Python
|
|
5
5
|
Home-page: https://github.com/giachello/pybeoplay
|
|
6
|
-
Download-URL: https://github.com/giachello/pybeoplay/tarball/2.
|
|
6
|
+
Download-URL: https://github.com/giachello/pybeoplay/tarball/2.4.0
|
|
7
7
|
Author: Giovanni Iachello
|
|
8
8
|
Author-email: giovanni.iachello@gmail.com
|
|
9
9
|
License: MIT License
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|