andito HF Staff commited on
Commit
91b6a1c
·
1 Parent(s): d683402

Add exponential backoff to all WebSocket clients; update setup step to mention dashboard login

Browse files
index.html CHANGED
@@ -70,7 +70,7 @@
70
  <li><strong>Create a Hugging Face account</strong> (free) at <a href="https://huggingface.co/join" target="_blank" style="color: #10b981; text-decoration: underline;">huggingface.co/join</a></li>
71
  <li><strong>Create an access token</strong> at <a href="https://huggingface.co/settings/tokens" target="_blank" style="color: #10b981; text-decoration: underline;">huggingface.co/settings/tokens</a> with 'read' permissions</li>
72
  <li><strong>Install this app</strong> on your Reachy Mini robot</li>
73
- <li><strong>Set your token:</strong> Open the app's settings page on your robot and paste your access token</li>
74
  <li><strong>Open the control interface</strong> in your browser and sign in with your Hugging Face account: <a href="https://huggingfacem4-reachy-mini-remote-control.hf.space" target="_blank" style="color: #10b981; text-decoration: underline;">huggingfacem4-reachy-mini-remote-control.hf.space</a></li>
75
  <li><strong>Start controlling!</strong> Your robot should appear connected in the interface</li>
76
  </ol>
 
70
  <li><strong>Create a Hugging Face account</strong> (free) at <a href="https://huggingface.co/join" target="_blank" style="color: #10b981; text-decoration: underline;">huggingface.co/join</a></li>
71
  <li><strong>Create an access token</strong> at <a href="https://huggingface.co/settings/tokens" target="_blank" style="color: #10b981; text-decoration: underline;">huggingface.co/settings/tokens</a> with 'read' permissions</li>
72
  <li><strong>Install this app</strong> on your Reachy Mini robot</li>
73
+ <li><strong>Log in to HuggingFace:</strong> Open the robot dashboard or desktop app and sign in with your HuggingFace account — the token is picked up automatically</li>
74
  <li><strong>Open the control interface</strong> in your browser and sign in with your Hugging Face account: <a href="https://huggingfacem4-reachy-mini-remote-control.hf.space" target="_blank" style="color: #10b981; text-decoration: underline;">huggingfacem4-reachy-mini-remote-control.hf.space</a></li>
75
  <li><strong>Start controlling!</strong> Your robot should appear connected in the interface</li>
76
  </ol>
src/reachy_mini_remote_control_app/websocket_clients/audio_stream.py CHANGED
@@ -67,6 +67,7 @@ class AsyncWebSocketAudioStreamer:
67
 
68
  async def _run(self) -> None:
69
  """Run the main reconnect loop."""
 
70
  while not self.stop_flag:
71
  try:
72
  # Add authentication header if token is provided
@@ -80,6 +81,7 @@ class AsyncWebSocketAudioStreamer:
80
  ) as ws:
81
  logger.info("[Audio Stream] Connected to remote server")
82
  self.connected.set()
 
83
 
84
  # Update connection status
85
  if self.monitor:
@@ -103,13 +105,14 @@ class AsyncWebSocketAudioStreamer:
103
  pass
104
 
105
  except Exception as e:
106
- logger.info(f"[Audio Stream] Connection failed: {e}")
107
 
108
  # Update connection status
109
  if self.monitor:
110
  self.monitor.update_audio_metrics(connected=False)
111
 
112
- await asyncio.sleep(1.0)
 
113
 
114
  self.connected.clear()
115
 
 
67
 
68
  async def _run(self) -> None:
69
  """Run the main reconnect loop."""
70
+ retry_delay = 1.0
71
  while not self.stop_flag:
72
  try:
73
  # Add authentication header if token is provided
 
81
  ) as ws:
82
  logger.info("[Audio Stream] Connected to remote server")
83
  self.connected.set()
84
+ retry_delay = 1.0 # Reset backoff on successful connection
85
 
86
  # Update connection status
87
  if self.monitor:
 
105
  pass
106
 
107
  except Exception as e:
108
+ logger.info(f"[Audio Stream] Connection failed: {e} (retrying in {retry_delay:.0f}s)")
109
 
110
  # Update connection status
111
  if self.monitor:
112
  self.monitor.update_audio_metrics(connected=False)
113
 
114
+ await asyncio.sleep(retry_delay)
115
+ retry_delay = min(retry_delay * 2, 60.0)
116
 
117
  self.connected.clear()
118
 
src/reachy_mini_remote_control_app/websocket_clients/robot_control.py CHANGED
@@ -101,6 +101,7 @@ class AsyncWebSocketController:
101
 
102
  async def _run(self) -> None:
103
  """Run the WebSocket controller loop with automatic reconnection."""
 
104
  while not self.stop_flag:
105
  try:
106
  ws: ClientConnection
@@ -116,6 +117,7 @@ class AsyncWebSocketController:
116
  additional_headers=extra_headers if extra_headers else None,
117
  ) as ws:
118
  logger.info("[Robot Control] Connected to remote server")
 
119
 
120
  # Update connection status
121
  if self.monitor:
@@ -133,14 +135,14 @@ class AsyncWebSocketController:
133
  await self.on_command(data)
134
 
135
  except Exception as e:
136
- logger.info("[Robot Control] Connection failed: %s", e)
137
 
138
  # Update connection status
139
  if self.monitor:
140
  self.monitor.update_control_metrics(connected=False)
141
 
142
- # Backoff before reconnect
143
- await asyncio.sleep(1)
144
 
145
  def stop(self) -> None:
146
  """Stop the WebSocket controller."""
 
101
 
102
  async def _run(self) -> None:
103
  """Run the WebSocket controller loop with automatic reconnection."""
104
+ retry_delay = 1.0
105
  while not self.stop_flag:
106
  try:
107
  ws: ClientConnection
 
117
  additional_headers=extra_headers if extra_headers else None,
118
  ) as ws:
119
  logger.info("[Robot Control] Connected to remote server")
120
+ retry_delay = 1.0 # Reset backoff on successful connection
121
 
122
  # Update connection status
123
  if self.monitor:
 
135
  await self.on_command(data)
136
 
137
  except Exception as e:
138
+ logger.info("[Robot Control] Connection failed: %s (retrying in %.0fs)", e, retry_delay)
139
 
140
  # Update connection status
141
  if self.monitor:
142
  self.monitor.update_control_metrics(connected=False)
143
 
144
+ await asyncio.sleep(retry_delay)
145
+ retry_delay = min(retry_delay * 2, 60.0)
146
 
147
  def stop(self) -> None:
148
  """Stop the WebSocket controller."""
src/reachy_mini_remote_control_app/websocket_clients/robot_state.py CHANGED
@@ -80,6 +80,7 @@ class AsyncWebSocketRobotStatePublisher:
80
  async def _run(self) -> None:
81
  """Run the WebSocket robot state publisher loop with automatic reconnection."""
82
  interval = 1.0 / self.update_rate
 
83
 
84
  while not self.stop_flag:
85
  try:
@@ -100,6 +101,7 @@ class AsyncWebSocketRobotStatePublisher:
100
  f"[Robot State] Connected to remote server, publishing at {self.update_rate} Hz"
101
  )
102
  self.connected.set()
 
103
 
104
  # Update connection status
105
  if self.monitor:
@@ -123,24 +125,15 @@ class AsyncWebSocketRobotStatePublisher:
123
  logger.error(f"[Robot State] Send error: {e}")
124
  break
125
 
126
- except ConnectionClosed as e:
127
- logger.error(f"[Robot State] Connection lost ({type(e).__name__}). Retrying...")
128
- self.connected.clear()
129
-
130
- # Update connection status
131
- if self.monitor:
132
- self.monitor.update_control_metrics(connected=False)
133
-
134
- await asyncio.sleep(0.5)
135
-
136
  except Exception as e:
137
- logger.error(f"[Robot State] Unexpected error: {e}")
138
 
139
  # Update connection status
140
  if self.monitor:
141
  self.monitor.update_control_metrics(connected=False)
142
 
143
- await asyncio.sleep(1)
 
144
 
145
  self.connected.clear()
146
 
 
80
  async def _run(self) -> None:
81
  """Run the WebSocket robot state publisher loop with automatic reconnection."""
82
  interval = 1.0 / self.update_rate
83
+ retry_delay = 1.0
84
 
85
  while not self.stop_flag:
86
  try:
 
101
  f"[Robot State] Connected to remote server, publishing at {self.update_rate} Hz"
102
  )
103
  self.connected.set()
104
+ retry_delay = 1.0 # Reset backoff on successful connection
105
 
106
  # Update connection status
107
  if self.monitor:
 
125
  logger.error(f"[Robot State] Send error: {e}")
126
  break
127
 
 
 
 
 
 
 
 
 
 
 
128
  except Exception as e:
129
+ logger.error(f"[Robot State] Connection error: {e} (retrying in {retry_delay:.0f}s)")
130
 
131
  # Update connection status
132
  if self.monitor:
133
  self.monitor.update_control_metrics(connected=False)
134
 
135
+ await asyncio.sleep(retry_delay)
136
+ retry_delay = min(retry_delay * 2, 60.0)
137
 
138
  self.connected.clear()
139
 
src/reachy_mini_remote_control_app/websocket_clients/video_stream.py CHANGED
@@ -70,6 +70,7 @@ class AsyncWebSocketFrameSender:
70
 
71
  async def _run(self) -> None:
72
  """Run the WebSocket frame sender loop with automatic reconnection."""
 
73
  while not self.stop_flag:
74
  try:
75
  ws: ClientConnection
@@ -88,6 +89,7 @@ class AsyncWebSocketFrameSender:
88
  logger.info("[Video Stream] Connected to remote server")
89
  self.connected.set()
90
  self._clear_queue()
 
91
 
92
  # Update connection status
93
  if self.monitor:
@@ -113,25 +115,15 @@ class AsyncWebSocketFrameSender:
113
  logger.error(f"[Video Stream] Send error: {e}")
114
  break
115
 
116
- except ConnectionClosed as e:
117
- logger.error(f"[Video Stream] Connection lost ({type(e).__name__}). Retrying...")
118
- self.connected.clear()
119
- self._last_frame = None
120
-
121
- # Update connection status
122
- if self.monitor:
123
- self.monitor.update_video_metrics(connected=False)
124
-
125
- await asyncio.sleep(0.5)
126
-
127
  except Exception as e:
128
- logger.error(f"[Video Stream] Unexpected error: {e}")
129
 
130
  # Update connection status
131
  if self.monitor:
132
  self.monitor.update_video_metrics(connected=False)
133
 
134
- await asyncio.sleep(1)
 
135
 
136
  self.connected.clear()
137
  self._last_frame = None
 
70
 
71
  async def _run(self) -> None:
72
  """Run the WebSocket frame sender loop with automatic reconnection."""
73
+ retry_delay = 1.0
74
  while not self.stop_flag:
75
  try:
76
  ws: ClientConnection
 
89
  logger.info("[Video Stream] Connected to remote server")
90
  self.connected.set()
91
  self._clear_queue()
92
+ retry_delay = 1.0 # Reset backoff on successful connection
93
 
94
  # Update connection status
95
  if self.monitor:
 
115
  logger.error(f"[Video Stream] Send error: {e}")
116
  break
117
 
 
 
 
 
 
 
 
 
 
 
 
118
  except Exception as e:
119
+ logger.error(f"[Video Stream] Connection error: {e} (retrying in {retry_delay:.0f}s)")
120
 
121
  # Update connection status
122
  if self.monitor:
123
  self.monitor.update_video_metrics(connected=False)
124
 
125
+ await asyncio.sleep(retry_delay)
126
+ retry_delay = min(retry_delay * 2, 60.0)
127
 
128
  self.connected.clear()
129
  self._last_frame = None