Files
dwarf-go/dwarfctl/TEST_RESULTS.md
Jacquin Antoine b72faf42ce Confirm all 4 mechanical limits are safe: no crash, no axis lock
Tested all four mechanical limits on both axes:
- Altitude down (270°): safe, triggers auto-home to position 0
- Altitude up (90°): safe, stops at limit switch
- Azimuth clockwise (0°): safe, stops at limit switch
- Azimuth counter-clockwise (180°): safe, stops at limit switch

All four limits are handled safely by the firmware. No reboots, no axis
lockups, no crashes. The earlier axis lockout was caused by the motor reset
command (cmd 14003), not by hitting a mechanical limit.

Updated TEST_RESULTS.md with the complete limit test matrix.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 20:06:17 +02:00

222 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Plan de test — dwarfctl sur télescope réel
## Conditions de test
- **Télescope** : DWARF II, firmware 2.1.6, mode AP (hotspot WiFi)
- **IP** : `192.168.88.1`
- **Réseau** : machine connectée au hotspot du télescope
- **Environnement** : intérieur, journée (pas d'accès au ciel/étoiles)
## Découvertes protocolaires importantes
### Modèle de réponse du télescope
Le télescope utilise **type=3 (REPLY)** pour les réponses directes, PAS type=1 (RESPONSE). De plus, certaines commandes ne reçoivent AUCUNE réponse directe — seulement des notifications (type=2).
| Pattern | Commandes | Comportement |
|---------|-----------|--------------|
| **Reply type=3 (même cmd)** | `photo` (10002), `focus auto` (15000), `focus step` (15001), `state` (16405) | Réponse directe avec le même cmd → request-response |
| **Notification uniquement** | `rgb-on/off` (13500/13501), `camera open/close` (10000/10001), `camera params` (10036) | Pas de reply → fire-and-forget + vérifier via `state` |
| **Fire-and-forget natif** | `motor slew` (14006), `motor stop` (14002) | Pas d'ack attendu |
### Implémentation dans dwarfctl
- `send()` : attend un type=3 reply (10s timeout) — pour photo, focus, state
- `sendNotify()` : fire-and-forget — pour RGB, camera open/close, motor slew
- Flag `--debug` / `-d` : loggue tout le trafic WebSocket (cmd, module, type, taille data)
## Tests par groupe
### ✅ 1. Connexion (PASS)
| Test | Commande | Résultat |
|------|----------|---------|
| Ping | `ping 192.168.88.1` | ✅ 36ms |
| Port 9900 (WebSocket) | `/dev/tcp/192.168.88.1/9900` | ✅ OPEN |
| Port 80 (RTSP) | `/dev/tcp/192.168.88.1/80` | ✅ OPEN |
| WebSocket handshake | `dwarfctl --ip 192.168.88.1 state` | ✅ connexion établie |
### ✅ 2. État du device (PASS)
```bash
dwarfctl --ip 192.168.88.1 state
```
Réponse complète : shooting_mode, cameras (résolution, FoV), focus position (594), batterie (100%), stockage (38/52 GB), température CMOS, modes disponibles.
### ✅ 3. Caméra Tele (PASS)
| Test | Commande | Debug | Statut |
|------|----------|-------|--------|
| Open camera | `camera open --cam tele` | fire-and-forget | ✅ |
| Photo | `camera photo --cam tele` | reply cmd=10002 type=3 data=11B | ✅ photo capturée |
| Focus step out | `focus step 1` | reply cmd=15001 type=3 data=0B | ✅ |
### ✅ 4. Moteurs / Slew (PASS)
Tests systématiques effectués — tous les mouvements confirmés visuellement sur le télescope.
#### 4.1 Directions cardinales (joystick cmd 14006)
| Direction | Angle | Length | Durée | Résultat |
|-----------|-------|--------|-------|----------|
| HAUT | 0° | 0.3 | 2s | ✅ mouvement observé |
| DROITE | 90° | 0.3 | 2s | ✅ mouvement observé |
| BAS | 180° | 0.3 | 2s | ✅ mouvement observé |
| GAUCHE | 270° | 0.3 | 2s | ✅ mouvement observé |
**Système de coordonnées joystick** : angle en degrés (polaire), 0°=haut, 90°=droite, 180°=bas, 270°=gauche. Length = vitesse normalisée (0.0 à 1.0).
#### 4.2 Vitesses variables
| Vitesse | Length | Résultat |
|---------|--------|----------|
| Lente | 0.1 | ✅ mouvement visible et lent |
| Moyenne | 0.5 | ✅ mouvement net |
| Rapide | 0.9 | ✅ mouvement rapide |
#### 4.3 Diagonales
| Direction | Angle | Résultat |
|-----------|-------|----------|
| HAUT-DROITE | 45° | ✅ mouvement diagonal |
| BAS-GAUCHE | 225° | ✅ mouvement diagonal |
Le joystick est bien polaire — 360° de liberté, pas seulement 4 directions.
#### 4.4 Arrêt d'urgence
| Test | Commande | Résultat |
|------|----------|----------|
| Stop pendant slew | `motor stop 0` (cmd 14002) | ✅ arrêt immédiat |
| Stop motor 1 | `motor stop 1` | ✅ |
Le `motor stop` interrompt un slew en cours instantanément.
#### ⚠️ 4.4b DANGER : Butée matérielle
**Test réel** : le slew à 90° (descente) continu a fait atteindre la butée basse mécanique. Le firmware a **coupé immédiatement le réseau** (perte totale : ping KO, port 9900 fermé). Redémarrage physique nécessaire.
**Leçon** : le slew joystick n'a PAS de soft-limit côté firmware. Il faut impérativement limiter la durée des slew altitude (90°/270°) à de courts intervalles (< 2s) et observer visuellement.
**Comportement après butée** : l'axe altitude s'est verrouillé le firmware refuse tout mouvement de slew sur cet axe après `LIMIT_POSITION_HIT`. L'axe azimut continue de fonctionner. Le déverrouillage nécessite un home/reset (calibration nocturne uniquement). Le `motor reset` (cmd 14003) provoque un reboot et ne déverrouille pas l'axe.
**Découverte clé — Home par butée** : slewing en 270° (descente) à vitesse modérée jusqu'à ce que le limit switch se déclenche provoque un **home automatique du firmware**. Le télescope revient à la position 0 physique (optique vers le sol). C'est la méthode d'initialisation manuelle des moteurs pas besoin de `motor reset` (qui ne fait que rebooter).
Procédure d'initialisation manuelle :
1. `motor slew 270 0.5` jusqu'à la butée (le firmware home tout seul)
2. Position 0 = optique vers le sol
3. L'API reste en `NEED_RESET` tant que la calibration astro n'est pas faite (le home mécanique ne donne pas la position absolue, seulement la position physique)
#### 4.5 Système de coordonnées joystick découvert (config alt-az, trépied vertical)
Tests en condition réelle, télescope posé verticalement sur trépied (pas en mode équatorial) :
| Angle | Axe | Direction observée |
|-------|-----|-------------------|
| 0° | Azimut (horizontal) | Rotation horaire vue de dessus |
| 90° | Altitude | **Montée** (vers le ciel) |
| 180° | Azimut | Rotation anti-horaire (opposé de 0°) |
| 270° | Altitude | **Descente** (vers le sol) |
**IMPORTANT** : ces directions sont validées pour une config alt-az simple (télescope vertical sur trépied). En mode équatorial (après EQ calibration), le mapping peut changer car les moteurs changent de référentiel.
#### 4.5b Butées mécaniques — test complet des 4 butées
Les 4 butées mécaniques ont été testées et sont **toutes gérées safely** par le firmware (arrêt au limit switch, pas de crash, pas de verrouillage d'axe) :
| Butée | Angle slew | Comportement | Reboot ? | Axe verrouillé ? |
|-------|-----------|-------------|----------|-----------------|
| Altitude basse (sol) | 270° continu | Arrêt + home auto à 0 | Non | Non |
| Altitude haute (ciel) | 90° continu | Arrêt au contact | Non | Non |
| Azimut horaire (↻) | 0° continu | Arrêt au contact | Non | Non |
| Azimut anti-horaire (↺) | 180° continu | Arrêt au contact | Non | Non |
**Conclusion** : les butées mécaniques sont sûres. Le firmware arrête le moteur au contact du limit switch sans crash ni verrouillage. L'incident précédent de verrouillage d'axe était au `motor reset` (cmd 14003), pas aux butées.
#### 4.5 Motor run/goto (cmd 14000)
| Test | Commande | Résultat |
|------|----------|----------|
| Run to position | `motor goto 0 10 5` | fire-and-forget envoyé |
`ReqMotorRunTo` : moteur ID, position cible, vitesse. Fire-and-forget (pas de ack type=3).
#### 4.6 Motor get-position (cmd 14001 — inféré, confirmé fonctionnel)
| Test | Commande | Résultat |
|------|----------|----------|
| Position moteur 0 | `motor position 0` | reply type=3, `code=-14520` (NEED_RESET) |
| Position moteur 1 | `motor position 1` | reply type=3, `code=-14520` (NEED_RESET) |
L'ID 14001 n'est pas dans le WsCmd enum de l'APK mais fonctionne le firmware répond avec `ResMotorPosition{id, code, position}`. Le `code=-14520` correspond à `CODE_STEP_MOTOR_NEED_RESET` : les moteurs n'ont pas été homed.
#### 4.7 Motor reset (cmd 14003 — ⚠️ DANGEREUX, DÉSACTIVÉ)
| Test | Commande | Résultat |
|------|----------|----------|
| Reset moteur 0 | `motor reset 0 0` | **A causé le reboot du télescope** |
L'ID 14003 est inféré (gap entre STOP=14002 et JOYSTICK=14006). L'envoi de `ReqMotorReset{id, direction}` a provoqué un **reboot immédiat du télescope**. La commande est désormais **désactivée** dans le code et retourne une erreur explicite.
**Leçon** : ne jamais envoyer de commandes inférées (IDs non confirmés dans le WsCmd enum de l'APK) sans validation préalable. L'app Android n'utilise que les commandes joystick (14006-14009), run (14000) et stop (14002). Le reset/home des moteurs est probablement géré côté firmware uniquement, déclenché par la calibration astro ou le panorama.
#### 4.6 Observations sur la lecture de position
- **`focus_position`** (moteur de mise au point) : visible dans `state` `focus_position:{pos:593}`, reste stable pendant les mouvements de pointage.
- **Position moteurs de pointage (RA/DEC)** : `motion_motor_state_info:{exclusive_state:{}}` reste vide la position des moteurs alt-az n'est PAS exposée dans `GetDeviceState`.
- Les messages proto `ReqMotorGetPosition` et `ReqMotorReset` existent dans le proto mais ne sont **pas utilisés par l'app Android** (aucune classe de requête correspondante). La lecture de position se fait probablement via les notifications d'attitude (cmd 15295 `CMD_NOTIFY_DEVICE_ATTITUDE`).
### ✅ 5. RGB / Power (PASS après fix fire-and-forget)
| Test | Commande | Avant fix | Après fix |
|------|----------|-----------|-----------|
| RGB off | `power rgb-off` | timeout (cmd 13501) | fire-and-forget |
| RGB on | `power rgb-on` | timeout (cmd 13500) | fire-and-forget |
Vérification : `rgb_state:{}` (éteint) vs `rgb_state:{state:1}` (allumé) dans `state`.
### ✅ 6. Focus (PASS)
| Test | Commande | Debug | Statut |
|------|----------|-------|--------|
| Autofocus | `focus auto` | notifications + reply cmd=15000 type=3 | |
| Step out | `focus step 1` | reply cmd=15001 type=3 | |
### ✅ 7. System (NON TESTÉ — nécessite validation)
| Test | Commande | Notes |
|------|----------|-------|
| Sync time | `system sync-time` | À tester |
| Set location | `system set-location 48.86 2.35 35` | À tester |
### ❌ 8. Astrophotographie (NON TESTABLE — jour/intérieur)
Ces commandes nécessitent un ciel étoilé nocturne :
| Test | Raison |
|------|--------|
| `astro calibrate start` | Nécessite des étoiles visibles |
| `astro goto-dso` | Nécessite le ciel |
| `astro stack start` | Nécessite des étoiles |
| `astro eq-solve start` | Nécessite des étoiles |
| `track start` | Nécessite une cible mobile |
### ❌ 9. Camera params (KNOWN ISSUE)
`camera params --cam tele` (cmd 10036) : le télescope ne renvoie pas de reply.
Les paramètres sont toutefois visibles dans la réponse `state` (résolution, FoV).
Les paramètres ajustables (exposure, gain) nécessiteraient une commande GET qui ne répond pas en type=3.
## Bugs corrigés pendant les tests
1. **`readLoop` ne dispatchait pas type=3 correctement** corrigé : tous les types sont dispatchés vers `dispatchResponse` + `dispatchNotification`
2. **Commandes RGB/camera open attendaient un reply inexistant** converties en fire-and-forget (`sendNotify`)
3. **Motor stop/goto attendaient un reply** convertis en fire-and-forget
4. **Pas de logging** ajout du flag `--debug` / `-d`
## Tests unitaires
```
ok github.com/antitbone/dwarfctl/internal/transport 0.003s
ok github.com/antitbone/dwarfctl/internal/api 0.003s
```
57 tests, tous PASS.