Commit Graph

13 Commits

Author SHA1 Message Date
c2f9e54eb4 Add camera streaming guide with all access methods
Comprehensive documentation for accessing the DWARF camera streams:
- RTSP URLs and channels (ch0=tele, ch1=wide)
- The critical prerequisite: camera must be opened via WebSocket first
- ffmpeg commands for frame capture, timelapse, and video recording
- mpv and VLC usage with TCP transport
- Python/OpenCV integration example
- Troubleshooting common issues (black image, connection refused, VLC delay)
- Comparison of RTSP vs MJPEG modes across device models

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-13 19:56:04 +02:00
7dc41ec368 Add RTSP preview capture — working with both cameras
Major breakthrough: RTSP preview fully operational on DWARF Mini.

Key discovery: RTSP (port 554) only works AFTER opening the camera via
WebSocket. Without CMD_CAMERA_OPEN (10000/12000), the RTSP server accepts
connections but never sends frames. This was the missing piece.

RTSP details:
- Tele: rtsp://<ip>:554/ch0/stream0
- Wide: rtsp://<ip>:554/ch1/stream0
- Codec: MJPEG over RTSP (not H.264)
- Transport: TCP (confirmed from RtspPlayerView.java ijkplayer options)
- Resolution: 1920x1080 both cameras

Port 8092 (MJPEG HTTP /mainstream, /secondstream) is inactive on the Mini.
The DWARF Mini uses RTSP exclusively, not the HTTP MJPEG fallback.

Added `dwarfctl preview grab [--cam tele|wide] [output.jpg]` that:
1. Opens the camera via WebSocket
2. Waits 2s for RTSP to become available
3. Captures one frame via ffmpeg

Updated API_REFERENCE.md with the corrected RTSP details and the camera-open
prerequisite.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-13 19:14:49 +02:00
4d2480c248 Implement working motor init command using limit-switch homing
Added `motor init [up|down] [timeout]` that homes the altitude axis by
slewing to a mechanical limit. The firmware detects the limit switch and
performs an automatic home to position 0 (optics toward ground).

Validated procedure:
1. Slew up briefly (90° 0.4 for 5s) to move away from the bottom limit
2. `motor init down 40` — slew 270° until bottom limit triggers auto-home
3. Axis remains fully operational after homing

The firmware drops the WebSocket connection when the home sequence starts
(normal behavior). After reconnecting, the axis works normally.

Note: API still returns NEED_RESET (-14520) because absolute positioning
requires astro calibration (plate solving). The mechanical home only
provides physical position 0, not sky coordinates.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 20:18:32 +02:00
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
3b349a6039 Document motor home via limit switch and manual init procedure
Discovered that slewing to the mechanical limit triggers an automatic
firmware home: the telescope returns to physical position 0 (optics down).
This is the manual motor initialization method — no reset command needed.

Position 0 = optics pointing toward the ground (straight down).
API still shows NEED_RESET until astro calibration provides absolute position.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 19:58:48 +02:00
897859b786 Fix calibration to include lon/lat params and document motor init flow
The calibration command (cmd 11000) requires lon/lat coordinates in the
ReqStartCalibration proto message — it was previously sent empty.
Added StartCalibrationWithLocation(lon, lat) method and updated the CLI.

Confirmed the complete motor initialization flow:
1. NEED_RESET (-14520) is NORMAL after every power-on
2. Slew (joystick) works in relative mode without absolute position
3. Only a successful astro calibration (night + stars + lon/lat) homes
   the motors and provides absolute positioning
4. After calibration, motor position returns code=0 with real coordinates
5. GoTo and tracking require calibration first
6. There is NO API command to initialize motors in daytime — the official
   app works identically (relative slew until night calibration)

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 19:53:30 +02:00
871021027b Add interactive slew mode and fix joystick coordinate mapping
- New `dwarfctl interactive` command: persistent WS connection with
  real-time slew commands on a single session (no reconnect per command).
  Decodes DeviceAttitude notifications (cmd 15295) when available.
- Fixed coordinate mapping: 90°=UP (toward sky), 270°=DOWN (toward ground),
  confirmed by live testing on DWARF II in alt-az config.
- Monitor now decodes attitude notifications inline.
- Note: IMU attitude (15295) is NOT pushed during free slew — only during
  calibration/EQ solving. Position feedback requires astro calibration.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:54:05 +02:00
5e23257822 Document altitude axis hardware lock after limit hit
The DWARF II firmware permanently locks the altitude motor axis after
hitting a mechanical limit. The lock survives reboots and motor resets.
Only a successful astro calibration (which homes all motors) clears it.
This is a firmware safety mechanism with no API bypass.

Motor reset (cmd 14003) reboots the device but does not unlock the axis.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:46:20 +02:00
2997cf327a Document post-limit behavior: altitude axis locks until calibration
After hitting the mechanical limit, the firmware locks the altitude axis
(rejects all slew commands on that axis). The azimuth axis continues to
work. Neither motor reset (causes reboot) nor power cycle unlocks it —
only a full astro calibration (which includes motor homing) restores
absolute positioning. This matches the NEED_RESET (-14520) error code.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:44:36 +02:00
9d07d13e97 Add health check command and panorama control
- New `dwarfctl health` command: checks WebSocket connectivity, device state,
  battery, storage, RGB, focus motor, both cameras, motor position status,
  and CMOS temperature in one pass with clear OK/FAIL output
- Added `dwarfctl pano start|stop` for panorama grid control
- Added StartPanoramaGrid/StopPanorama to the API client
- Fixed CMOS temperature display (int32 not float64)

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:42:18 +02:00
e7b97ad3d1 Document joystick coordinate system and hardware limit danger
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
2026-07-12 15:40:37 +02:00
c01a99093f Disable dangerous motor reset command after causing telescope reboot
The motor reset command (cmd 14003, inferred from a gap in the WsCmd enum)
caused the telescope to immediately reboot during live testing. The Android
app never uses ReqMotorReset — it only uses joystick (14006-14009), run
(14000) and stop (14002). Motor homing is handled internally by the firmware
during astro calibration or panorama operations.

Changes:
- MotorReset() now returns an error instead of sending the command
- CLI "motor reset" shows the disabled message
- Documented the incident and lessons in TEST_RESULTS.md
- Confirmed motor position query (cmd 14001) works but returns NEED_RESET
- Confirmed slew movements (all directions/speeds) work safely after reboot

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:24:11 +02:00
814a836c5a Reverse-engineer DWARF II telescope API and build open-source Go client
Complete reverse-engineering of the DWARFLAB Android app (v3.4.0) protocol
and implementation of a working CLI tool to control DWARF II telescopes.

Analysis (from APK decompilation with jadx):
- Extracted 17 protobuf definitions (382 messages) from embedded descriptors
- Mapped all 323 WebSocket command IDs across 16 modules
- Documented the full protocol: BLE discovery, WebSocket control (port 9900),
  RTSP preview, WsPacket envelope (proto v2.3)
- Documented the Android UI structure (screens, navigation, shooting modes)
- Key discovery: telescope responds with type=3 (reply), not type=1 (response),
  and several commands are fire-and-forget (RGB, camera open/close)

dwarfctl Go client:
- Protobuf bindings generated from extracted .proto files (397 messages)
- WebSocket transport layer with request-response matching and notification fan-out
- Typed API covering cameras, motors, astrophotography, focus, tracking, system, power
- Cobra CLI with 30+ subcommands and --debug traffic logging
- 57 unit tests (transport round-trip, command routing, proto encoding)
- Validated on real hardware: state, photo, motor slew (all directions/speeds),
  focus, RGB, time/location sync all confirmed working

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:18:56 +02:00