Files
dwarf-go/dwarfctl/README.md
Jacquin Antoine 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

3.3 KiB

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)