Desmond-Dong commited on
Commit
b9abf97
·
1 Parent(s): f45ab72

v0.6.2: Gesture detection with HaGRID ONNX models (18 gestures)

Browse files
PROJECT_PLAN.md CHANGED
@@ -387,11 +387,18 @@ Based on deep analysis of Reachy Mini SDK, the following entities are exposed to
387
  - [x] AudioPlayer integrates aiosendspin library
388
  - [x] TTS audio sent to both local speaker and Sendspin server
389
 
 
 
 
 
 
 
 
390
  ---
391
 
392
- ## 🎉 Phase 1-13 Entities Completed!
393
 
394
- **Total Completed: 43 entities**
395
  - Phase 1: 4 entities (Basic status and volume)
396
  - Phase 2: 4 entities (Motor control)
397
  - Phase 3: 9 entities (Pose control)
@@ -405,6 +412,7 @@ Based on deep analysis of Reachy Mini SDK, the following entities are exposed to
405
  - Phase 11: 0 entities (LED control - Disabled)
406
  - Phase 12: 4 entities (Audio processing parameters)
407
  - Phase 13: 3 entities (Sendspin audio output)
 
408
 
409
 
410
  ---
 
387
  - [x] AudioPlayer integrates aiosendspin library
388
  - [x] TTS audio sent to both local speaker and Sendspin server
389
 
390
+ 14. **Phase 22 - Gesture Detection** ✅ **Completed**
391
+ - [x] `gesture_detected` - Detected gesture name (Text Sensor)
392
+ - [x] `gesture_confidence` - Gesture detection confidence % (Sensor)
393
+ - [x] HaGRID ONNX models: hand_detector.onnx + crops_classifier.onnx
394
+ - [x] 18 supported gestures: call, dislike, fist, four, like, mute, ok, one, palm, peace, peace_inverted, rock, stop, stop_inverted, three, three2, two_up, two_up_inverted
395
+ - [x] Real-time state push to Home Assistant
396
+
397
  ---
398
 
399
+ ## 🎉 Phase 1-13 + Phase 22 Entities Completed!
400
 
401
+ **Total Completed: 45 entities**
402
  - Phase 1: 4 entities (Basic status and volume)
403
  - Phase 2: 4 entities (Motor control)
404
  - Phase 3: 9 entities (Pose control)
 
412
  - Phase 11: 0 entities (LED control - Disabled)
413
  - Phase 12: 4 entities (Audio processing parameters)
414
  - Phase 13: 3 entities (Sendspin audio output)
415
+ - Phase 22: 2 entities (Gesture detection)
416
 
417
 
418
  ---
changelog.json CHANGED
@@ -1,4 +1,13 @@
1
  [
 
 
 
 
 
 
 
 
 
2
  {
3
  "version": "0.6.1",
4
  "date": "2026-01-12",
 
1
  [
2
+ {
3
+ "version": "0.6.2",
4
+ "date": "2026-01-12",
5
+ "changes": [
6
+ "New: Gesture detection using HaGRID ONNX models (18 gesture classes)",
7
+ "New: gesture_detected and gesture_confidence entities in Home Assistant",
8
+ "Fix: Gesture state now properly pushed to Home Assistant in real-time"
9
+ ]
10
+ },
11
  {
12
  "version": "0.6.1",
13
  "date": "2026-01-12",
index.html CHANGED
@@ -90,6 +90,11 @@
90
  <h3>Sendspin Audio</h3>
91
  <p>Multi-room audio support via Sendspin protocol. Sync playback with other speakers in your home.</p>
92
  </div>
 
 
 
 
 
93
  </div>
94
  </section>
95
 
 
90
  <h3>Sendspin Audio</h3>
91
  <p>Multi-room audio support via Sendspin protocol. Sync playback with other speakers in your home.</p>
92
  </div>
93
+ <div class="feature-card">
94
+ <span class="icon">🤚</span>
95
+ <h3>Gesture Detection</h3>
96
+ <p>HaGRID-based hand gesture recognition with 18 gestures like thumbs up, peace sign, and more.</p>
97
+ </div>
98
  </div>
99
  </section>
100
 
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
 
5
  [project]
6
  name = "reachy_mini_ha_voice"
7
- version = "0.6.1"
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.6.2"
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.6.1"
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.6.2"
15
  __author__ = "Desmond Dong"
16
 
17
  # Don't import main module here to avoid runpy warning
reachy_mini_ha_voice/camera_server.py CHANGED
@@ -538,7 +538,7 @@ class MJPEGCameraServer:
538
  self._gesture_confidence = confidence
539
  if old_gesture != detected_gesture.value:
540
  state_changed = True
541
- _LOGGER.info("Gesture detected: %s (%.1f%%)",
542
  detected_gesture.value, confidence * 100)
543
  else:
544
  if self._current_gesture != "none":
@@ -550,8 +550,8 @@ class MJPEGCameraServer:
550
  if state_changed and self._gesture_state_callback:
551
  try:
552
  self._gesture_state_callback()
553
- except Exception as e:
554
- _LOGGER.debug("Gesture callback error: %s", e)
555
 
556
  except Exception as e:
557
  _LOGGER.warning("Gesture detection error: %s", e)
 
538
  self._gesture_confidence = confidence
539
  if old_gesture != detected_gesture.value:
540
  state_changed = True
541
+ _LOGGER.debug("Gesture: %s (%.0f%%)",
542
  detected_gesture.value, confidence * 100)
543
  else:
544
  if self._current_gesture != "none":
 
550
  if state_changed and self._gesture_state_callback:
551
  try:
552
  self._gesture_state_callback()
553
+ except Exception:
554
+ pass # Ignore callback errors
555
 
556
  except Exception as e:
557
  _LOGGER.warning("Gesture detection error: %s", e)
reachy_mini_ha_voice/gesture_detector.py CHANGED
@@ -166,13 +166,13 @@ class GestureDetector:
166
  if det is None:
167
  return Gesture.NONE, 0.0
168
  x1, y1, x2, y2, det_c = det
169
- logger.info("Hand detected: box=(%d,%d,%d,%d) conf=%.2f", x1, y1, x2, y2, det_c)
170
  crop = self._get_square_crop(frame, (x1, y1, x2, y2))
171
  if crop.size == 0:
172
  return Gesture.NONE, 0.0
173
  gest, cls_c = self._classify(crop)
174
  if gest != Gesture.NONE:
175
- logger.info("Gesture: %s (det=%.2f cls=%.2f)", gest.value, det_c, cls_c)
176
  return gest, det_c * cls_c
177
  except Exception as e:
178
  logger.warning("Gesture error: %s", e)
 
166
  if det is None:
167
  return Gesture.NONE, 0.0
168
  x1, y1, x2, y2, det_c = det
169
+ logger.debug("Hand: box=(%d,%d,%d,%d) conf=%.2f", x1, y1, x2, y2, det_c)
170
  crop = self._get_square_crop(frame, (x1, y1, x2, y2))
171
  if crop.size == 0:
172
  return Gesture.NONE, 0.0
173
  gest, cls_c = self._classify(crop)
174
  if gest != Gesture.NONE:
175
+ logger.debug("Gesture: %s (det=%.2f cls=%.2f)", gest.value, det_c, cls_c)
176
  return gest, det_c * cls_c
177
  except Exception as e:
178
  logger.warning("Gesture error: %s", e)