Files
dwarf-go/dwarfctl
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
..

dwarfctl — Open-source DWARF telescope control CLI

A Go command-line tool for controlling DWARF II (and upcoming DWARF III) smart telescopes over Wi-Fi via their WebSocket API.

Built from reverse-engineered protocol specs (see ../analysis/).

Quick start

make build
./dwarfctl --ip 192.168.1.100 state

Prerequisites

The telescope must be connected to your Wi-Fi (or your phone joined to the telescope's AP hotspot). Once you can ping the telescope's IP, dwarfctl can reach it.

Find the IP from:

  • The official DWARFLAB app's Settings → My Device
  • Your router's DHCP table (hostname like DWARFxxxx)
  • The BLE handshake (see ../analysis/API_REFERENCE.md)

Usage examples

# Device state
dwarfctl --ip 192.168.1.100 state

# Camera
dwarfctl camera open --cam tele
dwarfctl camera photo --cam tele
dwarfctl camera photo --cam wide --raw
dwarfctl camera burst start --cam tele
dwarfctl camera exp --cam tele 156       # 1/4s exposure
dwarfctl camera gain --cam tele 60
dwarfctl camera params --cam tele

# Motor / slew
dwarfctl motor slew 90 0.5               # angle 90°, half speed
dwarfctl motor stop 0                     # stop RA motor
dwarfctl motor goto 0 45.0 5.0           # RA motor to 45° at speed 5

# Astrophotography
dwarfctl astro calibrate start
dwarfctl astro goto-dso 10.6847 41.2687 "M31 Andromeda"
dwarfctl astro goto-solar 3              # Earth = index 3
dwarfctl astro stack start
dwarfctl astro eq-solve start            # polar alignment

# Focus
dwarfctl focus auto
dwarfctl focus step 1                     # 1=out, 0=in
dwarfctl focus astro-af start

# Tracking
dwarfctl track start 640 360 100 100 0   # bbox at center of tele cam
dwarfctl track stop

# System
dwarfctl system sync-time
dwarfctl system set-location 48.8566 2.3522 35

# Power
dwarfctl power rgb-on
dwarfctl power rgb-off
dwarfctl power reboot
dwarfctl power off

# Monitor notifications (live status events)
dwarfctl monitor

Architecture

dwarfctl/
├── proto/dwarf.proto          # unified proto3 definitions (397 messages)
├── proto/dwarf.pb.go          # generated Go bindings (24948 lines)
├── internal/
│   ├── transport/client.go    # WebSocket client + WsPacket envelope
│   └── api/
│       ├── commands.go        # 323 command IDs + module routing
│       └── client.go          # typed Telescope API (camera/motor/astro/...)
└── cmd/dwarfctl/main.go       # cobra CLI

Protocol summary

Layer Transport Port
Control WebSocket (binary protobuf) 9900
Preview RTSP (not implemented here) 554

Every command is a serialized WsPacket{major=2, minor=3, device_id, module_id, cmd, type, data, client_id}. The module_id is derived from cmd by range. See ../analysis/API_REFERENCE.md for details.

Regenerating protos

If the proto definitions change:

# From the APK analysis directory:
python3 ../analysis/extract_protos.py ../extracted/jadx/.../proto ../analysis/protos

# Merge into unified proto:
cd dwarfctl/proto
python3 merge.py . dwarf.proto
protoc --go_out=. --go_opt=paths=source_relative dwarf.proto

Roadmap

  • BLE discovery + handshake (DwarfPing/DwarfEcho)
  • RTSP preview viewer
  • Interactive REPL mode
  • Schedule plan management
  • OTA firmware update
  • Full Notify event parsing (typed)