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

244 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package api
// Module IDs (WsModuleId enum ordinals, derived from WsCmd.getModuleId ranges).
const (
ModuleNone = 0
ModuleCameraTele = 1
ModuleCameraWide = 2
ModuleAstro = 3
ModuleSystem = 4
ModuleRGBPower = 5
ModuleMotor = 6
ModuleTrack = 7
ModuleFocus = 8
ModuleNotify = 9
ModulePanorama = 10
ModuleITips = 11
ModuleShootingSchedule = 13
ModuleTaskCenter = 14
ModuleParam = 15
ModuleVoiceAssistant = 16
ModuleCameraGuide = 17
ModuleDevice = 18
)
// ModuleIDForCmd derives the module_id from a command ID using the same
// range logic as WsCmd.getModuleId() in the original APK.
func ModuleIDForCmd(cmd uint32) uint32 {
switch {
case cmd >= 10000 && cmd < 10500:
return ModuleCameraTele
case cmd >= 11000 && cmd < 11500:
return ModuleAstro
case cmd >= 12000 && cmd < 12500:
return ModuleCameraWide
case cmd >= 13000 && cmd < 13300:
return ModuleSystem
case cmd >= 13500 && cmd < 13800:
return ModuleRGBPower
case cmd >= 14000 && cmd < 14500:
return ModuleMotor
case cmd >= 14800 && cmd < 14900:
return ModuleTrack
case cmd >= 15000 && cmd < 15200:
return ModuleFocus
case cmd >= 15200 && cmd < 15500:
return ModuleNotify
case cmd >= 15500 && cmd < 15600:
return ModulePanorama
case cmd >= 15700 && cmd < 15800:
return ModuleITips
case cmd >= 16100 && cmd < 16400:
return ModuleShootingSchedule
case cmd >= 16400 && cmd < 16600:
return ModuleTaskCenter
case cmd >= 16700 && cmd < 16800:
return ModuleParam
case cmd >= 16800 && cmd < 16900:
return ModuleVoiceAssistant
case cmd >= 17000 && cmd < 17100:
return ModuleDevice
default:
return ModuleNone
}
}
// Command IDs — Camera Tele (MODULE_CAMERA_TELE, 1000010499).
const (
CmdTeleOpenCamera = 10000
CmdTeleCloseCamera = 10001
CmdTelePhotograph = 10002
CmdTeleBurst = 10003
CmdTeleStopBurst = 10004
CmdTeleStartRecord = 10005
CmdTeleStopRecord = 10006
CmdTeleSetExpMode = 10007
CmdTeleGetExpMode = 10008
CmdTeleSetExp = 10009
CmdTeleGetExp = 10010
CmdTeleSetGainMode = 10011
CmdTeleGetGainMode = 10012
CmdTeleSetGain = 10013
CmdTeleGetGain = 10014
CmdTeleSetBrightness = 10015
CmdTeleGetBrightness = 10016
CmdTeleSetContrast = 10017
CmdTeleGetContrast = 10018
CmdTeleSetSaturation = 10019
CmdTeleGetSaturation = 10020
CmdTeleSetHue = 10021
CmdTeleGetHue = 10022
CmdTeleSetSharpness = 10023
CmdTeleGetSharpness = 10024
CmdTeleSetWBMode = 10025
CmdTeleGetWBMode = 10026
CmdTeleSetWBScene = 10027
CmdTeleGetWBScene = 10028
CmdTeleSetWBCT = 10029
CmdTeleGetWBCT = 10030
CmdTeleSetIRCut = 10031
CmdTeleGetIRCut = 10032
CmdTeleStartTimelapse = 10033
CmdTeleStopTimelapse = 10034
CmdTeleSetAllParams = 10035
CmdTeleGetAllParams = 10036
CmdTeleSetFeatureParam = 10037
CmdTeleGetAllFeatureParams = 10038
CmdTeleGetWorkingState = 10039
CmdTeleSetJpgQuality = 10040
CmdTelePhotoRaw = 10041
CmdTeleSetRtspBitrate = 10042
CmdTeleSwitchResolution = 10047
CmdTeleSwitchFramerate = 10048
CmdTeleSwitchCropRatio = 10049
CmdTeleSetPreviewQuality = 10050
)
// Camera Wide (MODULE_CAMERA_WIDE, 1200012499).
const (
CmdWideOpenCamera = 12000
CmdWideCloseCamera = 12001
CmdWideSetExpMode = 12002
CmdWideGetExpMode = 12003
CmdWideSetExp = 12004
CmdWideGetExp = 12005
CmdWideSetGain = 12006
CmdWideGetGain = 12007
CmdWidePhotograph = 12022
CmdWideBurst = 12023
CmdWideStopBurst = 12024
CmdWidePhotoRaw = 12029
CmdWideStartRecord = 12030
CmdWideStopRecord = 12031
CmdWideGetAllParams = 12027
CmdWideSetAllParams = 12028
)
// Astro (MODULE_ASTRO, 1100011499).
const (
CmdAstroStartCalibration = 11000
CmdAstroStopCalibration = 11001
CmdAstroStartGotoDSO = 11002
CmdAstroStartGotoSolar = 11003
CmdAstroStopGoto = 11004
CmdAstroStartLiveStacking = 11005
CmdAstroStopLiveStacking = 11006
CmdAstroStartRawDark = 11007
CmdAstroStopRawDark = 11008
CmdAstroGoLive = 11010
CmdAstroStartOneClickGoto = 11013
CmdAstroStopOneClickGoto = 11015
CmdAstroStartEqSolving = 11018
CmdAstroStopEqSolving = 11019
CmdAstroStartAiEnhance = 11029
CmdAstroStopAiEnhance = 11030
CmdAstroStartMosaic = 11031
CmdAstroStartSkyFinder = 11047
CmdAstroStopSkyFinder = 11048
)
// System (MODULE_SYSTEM, 1300013299).
const (
CmdSystemSetTime = 13000
CmdSystemSetTimeZone = 13001
CmdSystemSetMtpMode = 13002
CmdSystemSetCpuMode = 13003
CmdSystemSetMasterLock = 13004
CmdSystemSetLocation = 13010
)
// RGB Power (MODULE_RGB_POWER, 1350013799).
const (
CmdRGBOn = 13500
CmdRGBOff = 13501
CmdPowerDown = 13502
CmdReboot = 13505
)
// Motor constants — extended (14001-14005 are inferred from gaps)
const (
CmdMotorRun = 14000
CmdMotorGetPosition = 14001 // inferred: missing ID between RUN and STOP
CmdMotorStop = 14002
CmdMotorReset = 14003 // inferred: missing ID after STOP
CmdMotorChangeSpeed = 14004 // inferred
CmdMotorChangeDirection = 14005 // inferred
CmdMotorJoystick = 14006
CmdMotorJoystickFixedAngle = 14007
CmdMotorJoystickStop = 14008
CmdMotorDualCameraLinkage = 14009
)
// Track (MODULE_TRACK, 1480014899).
const (
CmdTrackStart = 14800
CmdTrackStop = 14801
CmdSentryStart = 14802
CmdSentryStop = 14803
CmdSwitchMainPreview = 14809
)
// Focus (MODULE_FOCUS, 1500015199).
const (
CmdFocusAutoFocus = 15000
CmdFocusManualSingle = 15001
CmdFocusStartManualCont = 15002
CmdFocusStopManualCont = 15003
CmdFocusStartAstroAF = 15004
CmdFocusStopAstroAF = 15005
CmdFocusGetUserInfinity = 15011
CmdFocusSetUserInfinity = 15012
)
// Panorama (MODULE_PANORAMA, 1550015599).
const (
CmdPanoStartGrid = 15500
CmdPanoStop = 15501
CmdPanoStartStitch = 15503
CmdPanoStopStitch = 15504
CmdPanoStartFraming = 15509
CmdPanoStopFraming = 15510
CmdPanoResetFraming = 15511
CmdPanoUpdateFramingRect = 15512
)
// Task Center (MODULE_TASK_CENTER, 1640016599).
const (
CmdTaskStartTask = 16400
CmdTaskStopTask = 16401
CmdTaskSwitchMode = 16402
CmdTaskSwitchTech = 16403
CmdTaskGetDeviceState = 16405
)
// Notify (MODULE_NOTIFY, 1520015399) — server-pushed, not requestable.
const (
NotifyTrackResult = 15225
NotifyStateCaptureRawDark = 15206
NotifyCalibrationResult = 15256
NotifyStateAstroGoto = 15211
NotifyTemperature = 15243
NotifySDCardInfo = 15203
NotifyPowerOff = 15229
)