PyChromecast 14.0.3__tar.gz → 14.0.4__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 (48) hide show
  1. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PKG-INFO +1 -1
  2. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PyChromecast.egg-info/PKG-INFO +1 -1
  3. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PyChromecast.egg-info/SOURCES.txt +1 -0
  4. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/const.py +2 -0
  5. PyChromecast-14.0.4/pychromecast/controllers/heartbeat.py +90 -0
  6. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/socket_client.py +19 -83
  7. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pyproject.toml +1 -1
  8. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/LICENSE +0 -0
  9. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/MANIFEST.in +0 -0
  10. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PyChromecast.egg-info/dependency_links.txt +0 -0
  11. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PyChromecast.egg-info/not-zip-safe +0 -0
  12. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PyChromecast.egg-info/requires.txt +0 -0
  13. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/PyChromecast.egg-info/top_level.txt +0 -0
  14. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/README.rst +0 -0
  15. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/__init__.py +0 -0
  16. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/config.py +0 -0
  17. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/__init__.py +0 -0
  18. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/bbciplayer.py +0 -0
  19. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/bbcsounds.py +0 -0
  20. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/bubbleupnp.py +0 -0
  21. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/dashcast.py +0 -0
  22. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/homeassistant.py +0 -0
  23. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/homeassistant_media.py +0 -0
  24. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/media.py +0 -0
  25. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/multizone.py +0 -0
  26. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/nrkradio.py +0 -0
  27. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/nrktv.py +0 -0
  28. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/plex.py +0 -0
  29. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/receiver.py +0 -0
  30. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/shaka.py +0 -0
  31. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/supla.py +0 -0
  32. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/yleareena.py +0 -0
  33. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/controllers/youtube.py +0 -0
  34. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/dial.py +0 -0
  35. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/discovery.py +0 -0
  36. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/error.py +0 -0
  37. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/authority_keys_pb2.py +0 -0
  38. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/authority_keys_pb2.pyi +0 -0
  39. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/cast_channel_pb2.py +0 -0
  40. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/cast_channel_pb2.pyi +0 -0
  41. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/logging_pb2.py +0 -0
  42. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/logging_pb2.pyi +0 -0
  43. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/generated/readme.txt +0 -0
  44. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/models.py +0 -0
  45. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/quick_play.py +0 -0
  46. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/pychromecast/response_handler.py +0 -0
  47. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/requirements.txt +0 -0
  48. {PyChromecast-14.0.3 → PyChromecast-14.0.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChromecast
3
- Version: 14.0.3
3
+ Version: 14.0.4
4
4
  Summary: Python module to talk to Google Chromecast.
5
5
  Author-email: Paulus Schoutsen <paulus@paulusschoutsen.nl>
6
6
  Project-URL: Homepage, https://github.com/home-assistant-libs/pychromecast
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyChromecast
3
- Version: 14.0.3
3
+ Version: 14.0.4
4
4
  Summary: Python module to talk to Google Chromecast.
5
5
  Author-email: Paulus Schoutsen <paulus@paulusschoutsen.nl>
6
6
  Project-URL: Homepage, https://github.com/home-assistant-libs/pychromecast
@@ -25,6 +25,7 @@ pychromecast/controllers/bbciplayer.py
25
25
  pychromecast/controllers/bbcsounds.py
26
26
  pychromecast/controllers/bubbleupnp.py
27
27
  pychromecast/controllers/dashcast.py
28
+ pychromecast/controllers/heartbeat.py
28
29
  pychromecast/controllers/homeassistant.py
29
30
  pychromecast/controllers/homeassistant_media.py
30
31
  pychromecast/controllers/media.py
@@ -70,3 +70,5 @@ CAST_TYPES = {
70
70
  MESSAGE_TYPE = "type"
71
71
  REQUEST_ID = "requestId"
72
72
  SESSION_ID = "sessionId"
73
+
74
+ PLATFORM_DESTINATION_ID = "receiver-0"
@@ -0,0 +1,90 @@
1
+ """Controller to send and respond to heartbeat messages."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import time
7
+
8
+ from . import BaseController
9
+
10
+ from ..const import MESSAGE_TYPE, PLATFORM_DESTINATION_ID
11
+ from ..error import ControllerNotRegistered, NotConnected, PyChromecastStopped
12
+
13
+ # pylint: disable-next=no-name-in-module
14
+ from ..generated.cast_channel_pb2 import CastMessage
15
+
16
+ NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat"
17
+
18
+ TYPE_PING = "PING"
19
+ TYPE_PONG = "PONG"
20
+
21
+ HB_PING_TIME = 10
22
+ HB_PONG_TIME = 10
23
+
24
+
25
+ class HeartbeatController(BaseController):
26
+ """Controller to send and respond to heartbeat messages."""
27
+
28
+ def __init__(self) -> None:
29
+ super().__init__(NS_HEARTBEAT, target_platform=True)
30
+ self.last_ping = 0.0
31
+ self.last_pong = time.time()
32
+ self.logger = logging.getLogger(__name__)
33
+
34
+ def receive_message(self, _message: CastMessage, data: dict) -> bool:
35
+ """
36
+ Called when a heartbeat message is received.
37
+
38
+ data is message.payload_utf8 interpreted as a JSON dict.
39
+ """
40
+ if self._socket_client is None:
41
+ raise ControllerNotRegistered
42
+
43
+ if self._socket_client.is_stopped:
44
+ return True
45
+
46
+ if data[MESSAGE_TYPE] == TYPE_PING:
47
+ try:
48
+ self._socket_client.send_message(
49
+ PLATFORM_DESTINATION_ID,
50
+ self.namespace,
51
+ {MESSAGE_TYPE: TYPE_PONG},
52
+ no_add_request_id=True,
53
+ )
54
+ except PyChromecastStopped:
55
+ self._socket_client.logger.debug(
56
+ "Heartbeat error when sending response, "
57
+ "Chromecast connection has stopped"
58
+ )
59
+
60
+ return True
61
+
62
+ if data[MESSAGE_TYPE] == TYPE_PONG:
63
+ self.reset()
64
+ return True
65
+
66
+ return False
67
+
68
+ def ping(self) -> None:
69
+ """Send a ping message."""
70
+ if self._socket_client is None:
71
+ raise ControllerNotRegistered
72
+
73
+ self.last_ping = time.time()
74
+ try:
75
+ self.send_message({MESSAGE_TYPE: TYPE_PING})
76
+ except NotConnected:
77
+ self._socket_client.logger.error(
78
+ "Chromecast is disconnected. Cannot ping until reconnected."
79
+ )
80
+
81
+ def reset(self) -> None:
82
+ """Reset expired counter."""
83
+ self.last_pong = time.time()
84
+
85
+ def is_expired(self) -> bool:
86
+ """Indicates if connection has expired."""
87
+ if time.time() - self.last_ping > HB_PING_TIME:
88
+ self.ping()
89
+
90
+ return (time.time() - self.last_pong) > HB_PING_TIME + HB_PONG_TIME
@@ -24,8 +24,9 @@ from struct import pack, unpack
24
24
 
25
25
  import zeroconf
26
26
 
27
- from .const import MESSAGE_TYPE, REQUEST_ID, SESSION_ID
27
+ from .const import MESSAGE_TYPE, PLATFORM_DESTINATION_ID, REQUEST_ID, SESSION_ID
28
28
  from .controllers import BaseController, CallbackType
29
+ from .controllers.heartbeat import NS_HEARTBEAT, HeartbeatController
29
30
  from .controllers.media import MediaController
30
31
  from .controllers.receiver import CastStatus, CastStatusListener, ReceiverController
31
32
  from .dial import get_host_from_service
@@ -42,12 +43,7 @@ from .generated.cast_channel_pb2 import CastMessage
42
43
  from .models import HostServiceInfo, MDNSServiceInfo
43
44
 
44
45
  NS_CONNECTION = "urn:x-cast:com.google.cast.tp.connection"
45
- NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat"
46
46
 
47
- PLATFORM_DESTINATION_ID = "receiver-0"
48
-
49
- TYPE_PING = "PING"
50
- TYPE_PONG = "PONG"
51
47
  TYPE_CONNECT = "CONNECT"
52
48
  TYPE_CLOSE = "CLOSE"
53
49
  TYPE_LOAD = "LOAD"
@@ -65,10 +61,7 @@ CONNECTION_STATUS_FAILED_RESOLVE = "FAILED_RESOLVE"
65
61
  # The socket connection was lost and needs to be retried
66
62
  CONNECTION_STATUS_LOST = "LOST"
67
63
 
68
- HB_PING_TIME = 10
69
- HB_PONG_TIME = 10
70
- POLL_TIME_BLOCKING = 5.0
71
- POLL_TIME_NON_BLOCKING = 0.01
64
+ SELECT_TIMEOUT = 5.0
72
65
  TIMEOUT_TIME = 30.0
73
66
  RETRY_TIME = 5.0
74
67
 
@@ -540,7 +533,7 @@ class SocketClient(threading.Thread, CastStatusListener):
540
533
  self.logger.debug("Thread started...")
541
534
  while not self.stop.is_set():
542
535
  try:
543
- if self._run_once(timeout=POLL_TIME_BLOCKING) == 1:
536
+ if self._run_once() == 1:
544
537
  break
545
538
  except Exception: # pylint: disable=broad-except
546
539
  self._force_recon = True
@@ -555,7 +548,7 @@ class SocketClient(threading.Thread, CastStatusListener):
555
548
  # Clean up
556
549
  self._cleanup()
557
550
 
558
- def _run_once(self, timeout: float = POLL_TIME_NON_BLOCKING) -> int:
551
+ def _run_once(self) -> int:
559
552
  """Receive from the socket and handle data."""
560
553
  # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements
561
554
 
@@ -568,9 +561,13 @@ class SocketClient(threading.Thread, CastStatusListener):
568
561
  # A connection has been established at this point by self._check_connection
569
562
  assert self.socket is not None
570
563
 
571
- # poll the socket, as well as the socketpair to allow us to be interrupted
564
+ # Poll the socket and the socketpair, with a timeout of SELECT_TIMEOUT
565
+ # The timeout ensures we call _check_connection often enough to avoid
566
+ # the HeartbeatController from detecting a timeout
567
+ # The socketpair allow us to be interrupted on shutdown without waiting
568
+ # for the SELECT_TIMEOUT timout to expire
572
569
  try:
573
- ready = self.selector.select(timeout)
570
+ ready = self.selector.select(SELECT_TIMEOUT)
574
571
  except (ValueError, OSError) as exc:
575
572
  self.logger.error(
576
573
  "[%s(%s):%s] Error in select call: %s",
@@ -689,7 +686,10 @@ class SocketClient(threading.Thread, CastStatusListener):
689
686
  # route message to handlers
690
687
  if message.namespace in self._handlers:
691
688
  # debug messages
692
- if message.namespace != NS_HEARTBEAT:
689
+ if (
690
+ message.namespace != NS_HEARTBEAT
691
+ or self.heartbeat_controller.logger.isEnabledFor(logging.DEBUG)
692
+ ):
693
693
  self.logger.debug(
694
694
  "[%s(%s):%s] Received: %s",
695
695
  self.fn or "",
@@ -873,7 +873,10 @@ class SocketClient(threading.Thread, CastStatusListener):
873
873
  be_size = pack(">I", msg.ByteSize())
874
874
 
875
875
  # Log all messages except heartbeat
876
- if msg.namespace != NS_HEARTBEAT:
876
+ if (
877
+ msg.namespace != NS_HEARTBEAT
878
+ or self.heartbeat_controller.logger.isEnabledFor(logging.DEBUG)
879
+ ):
877
880
  self.logger.debug(
878
881
  "[%s(%s):%s] Sending: %s",
879
882
  self.fn or "",
@@ -1062,73 +1065,6 @@ class ConnectionController(BaseController):
1062
1065
  return False
1063
1066
 
1064
1067
 
1065
- class HeartbeatController(BaseController):
1066
- """Controller to respond to heartbeat messages."""
1067
-
1068
- def __init__(self) -> None:
1069
- super().__init__(NS_HEARTBEAT, target_platform=True)
1070
- self.last_ping = 0.0
1071
- self.last_pong = time.time()
1072
-
1073
- def receive_message(self, _message: CastMessage, data: dict) -> bool:
1074
- """
1075
- Called when a heartbeat message is received.
1076
-
1077
- data is message.payload_utf8 interpreted as a JSON dict.
1078
- """
1079
- if self._socket_client is None:
1080
- raise ControllerNotRegistered
1081
-
1082
- if self._socket_client.is_stopped:
1083
- return True
1084
-
1085
- if data[MESSAGE_TYPE] == TYPE_PING:
1086
- try:
1087
- self._socket_client.send_message(
1088
- PLATFORM_DESTINATION_ID,
1089
- self.namespace,
1090
- {MESSAGE_TYPE: TYPE_PONG},
1091
- no_add_request_id=True,
1092
- )
1093
- except PyChromecastStopped:
1094
- self._socket_client.logger.debug(
1095
- "Heartbeat error when sending response, "
1096
- "Chromecast connection has stopped"
1097
- )
1098
-
1099
- return True
1100
-
1101
- if data[MESSAGE_TYPE] == TYPE_PONG:
1102
- self.reset()
1103
- return True
1104
-
1105
- return False
1106
-
1107
- def ping(self) -> None:
1108
- """Send a ping message."""
1109
- if self._socket_client is None:
1110
- raise ControllerNotRegistered
1111
-
1112
- self.last_ping = time.time()
1113
- try:
1114
- self.send_message({MESSAGE_TYPE: TYPE_PING})
1115
- except NotConnected:
1116
- self._socket_client.logger.error(
1117
- "Chromecast is disconnected. Cannot ping until reconnected."
1118
- )
1119
-
1120
- def reset(self) -> None:
1121
- """Reset expired counter."""
1122
- self.last_pong = time.time()
1123
-
1124
- def is_expired(self) -> bool:
1125
- """Indicates if connection has expired."""
1126
- if time.time() - self.last_ping > HB_PING_TIME:
1127
- self.ping()
1128
-
1129
- return (time.time() - self.last_pong) > HB_PING_TIME + HB_PONG_TIME
1130
-
1131
-
1132
1068
  def new_socket() -> socket.socket:
1133
1069
  """
1134
1070
  Create a new socket with OS-specific parameters
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyChromecast"
7
- version = "14.0.3"
7
+ version = "14.0.4"
8
8
  description = "Python module to talk to Google Chromecast."
9
9
  readme = "README.rst"
10
10
  authors = [
File without changes
File without changes
File without changes
File without changes