Live testing revealed the joystick polar coordinate mapping (alt-az config):
- 0° = azimuth rotation clockwise (viewed from above)
- 90° = altitude DOWN (toward ground)
- 180° = azimuth counter-clockwise
- 270° = altitude UP (toward sky)
Also discovered that continuous slew to a mechanical limit causes the
firmware to emergency-stop and drop the network connection entirely,
requiring a physical power cycle. No soft-limit protection exists for
joystick slew commands.
Updated TEST_RESULTS.md with the coordinate map and safety warning.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
200 lines
9.3 KiB
Markdown
200 lines
9.3 KiB
Markdown
# 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.
|
||
|
||
#### 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 | **Descente** (vers le sol) |
|
||
| 180° | Azimut | Rotation anti-horaire (opposé de 0°) |
|
||
| 270° | Altitude | **Montée** (vers le ciel) |
|
||
|
||
**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.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.
|