Desmond-Dong commited on
Commit
5f89e0d
·
1 Parent(s): be4ed94

v0.2.4: Fix microphone volume control - Use daemon HTTP API (/api/volume/microphone/set) instead of ReSpeaker DSP parameters - This matches the official implementation using amixer commands

Browse files
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
 
5
  [project]
6
  name = "reachy_mini_ha_voice"
7
- version = "0.2.3"
8
  description = "Home Assistant Voice Assistant for Reachy Mini"
9
  readme = "README.md"
10
  requires-python = ">=3.10"
 
4
 
5
  [project]
6
  name = "reachy_mini_ha_voice"
7
+ version = "0.2.4"
8
  description = "Home Assistant Voice Assistant for Reachy Mini"
9
  readme = "README.md"
10
  requires-python = ">=3.10"
reachy_mini_ha_voice/__init__.py CHANGED
@@ -11,7 +11,7 @@ Key features:
11
  - Reachy Mini motion control integration
12
  """
13
 
14
- __version__ = "0.2.3"
15
  __author__ = "Desmond Dong"
16
 
17
  # Don't import main module here to avoid runpy warning
 
11
  - Reachy Mini motion control integration
12
  """
13
 
14
+ __version__ = "0.2.4"
15
  __author__ = "Desmond Dong"
16
 
17
  # Don't import main module here to avoid runpy warning
reachy_mini_ha_voice/reachy_controller.py CHANGED
@@ -137,32 +137,34 @@ class ReachyController:
137
  logger.error(f"Error setting speaker volume: {e}")
138
 
139
  def get_microphone_volume(self) -> float:
140
- """Get microphone volume (0-100) using local SDK audio interface."""
141
- respeaker = self._get_respeaker()
142
- if respeaker is None:
143
  return getattr(self, '_microphone_volume', 50.0)
144
-
145
- # Try different gain parameters (varies by ReSpeaker model)
146
- gain_params = [
147
- ("AGCGAIN", 31.0), # AGC target level (0-31)
148
- ("MICGAIN", 31.0), # Microphone gain
149
- ]
150
-
151
- for param_name, max_val in gain_params:
152
- try:
153
- result = respeaker.read(param_name)
154
- if result is not None:
155
- self._microphone_volume = (result[0] / max_val) * 100.0
156
- logger.debug(f"Read microphone volume: {self._microphone_volume}% ({param_name}: {result[0]})")
157
- return self._microphone_volume
158
- except Exception as e:
159
- logger.debug(f"Could not read {param_name}: {e}")
160
-
 
 
 
161
  return getattr(self, '_microphone_volume', 50.0)
162
 
163
  def set_microphone_volume(self, volume: float) -> None:
164
  """
165
- Set microphone volume (0-100) using local SDK audio interface.
166
 
167
  Args:
168
  volume: Volume level 0-100
@@ -170,27 +172,30 @@ class ReachyController:
170
  volume = max(0.0, min(100.0, volume))
171
  self._microphone_volume = volume
172
 
173
- respeaker = self._get_respeaker()
174
- if respeaker is None:
175
- logger.warning("Cannot set microphone volume: ReSpeaker not available")
176
  return
177
 
178
- # Try different gain parameters (varies by ReSpeaker model)
179
- gain_params = [
180
- ("AGCGAIN", 31.0), # AGC target level (0-31)
181
- ("MICGAIN", 31.0), # Microphone gain
182
- ]
183
-
184
- for param_name, max_val in gain_params:
185
- try:
186
- gain = int((volume / 100.0) * max_val)
187
- respeaker.write(param_name, [gain])
188
- logger.info(f"Microphone volume set to {volume}% ({param_name}: {gain})")
189
- return # Success, stop trying other params
190
- except Exception as e:
191
- logger.debug(f"Could not write {param_name}: {e}")
192
-
193
- logger.error("Failed to set microphone volume: no supported parameter found")
 
 
 
 
194
 
195
  # ========== Phase 2: Motor Control ==========
196
 
 
137
  logger.error(f"Error setting speaker volume: {e}")
138
 
139
  def get_microphone_volume(self) -> float:
140
+ """Get microphone volume (0-100) using daemon HTTP API."""
141
+ if not self.is_available:
 
142
  return getattr(self, '_microphone_volume', 50.0)
143
+
144
+ try:
145
+ # Get WLAN IP from cached daemon status
146
+ status = self._get_cached_status()
147
+ if status is None:
148
+ return getattr(self, '_microphone_volume', 50.0)
149
+ wlan_ip = status.get('wlan_ip', 'localhost')
150
+
151
+ # Call the daemon API to get microphone volume
152
+ response = requests.get(
153
+ f"http://{wlan_ip}:8000/api/volume/microphone/current",
154
+ timeout=2
155
+ )
156
+ if response.status_code == 200:
157
+ data = response.json()
158
+ self._microphone_volume = float(data.get('volume', 50))
159
+ return self._microphone_volume
160
+ except Exception as e:
161
+ logger.debug(f"Could not get microphone volume from API: {e}")
162
+
163
  return getattr(self, '_microphone_volume', 50.0)
164
 
165
  def set_microphone_volume(self, volume: float) -> None:
166
  """
167
+ Set microphone volume (0-100) using daemon HTTP API.
168
 
169
  Args:
170
  volume: Volume level 0-100
 
172
  volume = max(0.0, min(100.0, volume))
173
  self._microphone_volume = volume
174
 
175
+ if not self.is_available:
176
+ logger.warning("Cannot set microphone volume: robot not available")
 
177
  return
178
 
179
+ try:
180
+ # Get WLAN IP from cached daemon status
181
+ status = self._get_cached_status()
182
+ if status is None:
183
+ logger.error("Cannot get daemon status for microphone volume control")
184
+ return
185
+ wlan_ip = status.get('wlan_ip', 'localhost')
186
+
187
+ # Call the daemon API to set microphone volume
188
+ response = requests.post(
189
+ f"http://{wlan_ip}:8000/api/volume/microphone/set",
190
+ json={"volume": int(volume)},
191
+ timeout=5
192
+ )
193
+ if response.status_code == 200:
194
+ logger.info(f"Microphone volume set to {volume}%")
195
+ else:
196
+ logger.error(f"Failed to set microphone volume: {response.status_code} {response.text}")
197
+ except Exception as e:
198
+ logger.error(f"Error setting microphone volume: {e}")
199
 
200
  # ========== Phase 2: Motor Control ==========
201