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
244 lines
7.1 KiB
Go
244 lines
7.1 KiB
Go
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, 10000–10499).
|
||
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, 12000–12499).
|
||
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, 11000–11499).
|
||
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, 13000–13299).
|
||
const (
|
||
CmdSystemSetTime = 13000
|
||
CmdSystemSetTimeZone = 13001
|
||
CmdSystemSetMtpMode = 13002
|
||
CmdSystemSetCpuMode = 13003
|
||
CmdSystemSetMasterLock = 13004
|
||
CmdSystemSetLocation = 13010
|
||
)
|
||
|
||
// RGB Power (MODULE_RGB_POWER, 13500–13799).
|
||
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, 14800–14899).
|
||
const (
|
||
CmdTrackStart = 14800
|
||
CmdTrackStop = 14801
|
||
CmdSentryStart = 14802
|
||
CmdSentryStop = 14803
|
||
CmdSwitchMainPreview = 14809
|
||
)
|
||
|
||
// Focus (MODULE_FOCUS, 15000–15199).
|
||
const (
|
||
CmdFocusAutoFocus = 15000
|
||
CmdFocusManualSingle = 15001
|
||
CmdFocusStartManualCont = 15002
|
||
CmdFocusStopManualCont = 15003
|
||
CmdFocusStartAstroAF = 15004
|
||
CmdFocusStopAstroAF = 15005
|
||
CmdFocusGetUserInfinity = 15011
|
||
CmdFocusSetUserInfinity = 15012
|
||
)
|
||
|
||
// Panorama (MODULE_PANORAMA, 15500–15599).
|
||
const (
|
||
CmdPanoStartGrid = 15500
|
||
CmdPanoStop = 15501
|
||
CmdPanoStartStitch = 15503
|
||
CmdPanoStopStitch = 15504
|
||
CmdPanoStartFraming = 15509
|
||
CmdPanoStopFraming = 15510
|
||
CmdPanoResetFraming = 15511
|
||
CmdPanoUpdateFramingRect = 15512
|
||
)
|
||
|
||
// Task Center (MODULE_TASK_CENTER, 16400–16599).
|
||
const (
|
||
CmdTaskStartTask = 16400
|
||
CmdTaskStopTask = 16401
|
||
CmdTaskSwitchMode = 16402
|
||
CmdTaskSwitchTech = 16403
|
||
CmdTaskGetDeviceState = 16405
|
||
)
|
||
|
||
// Notify (MODULE_NOTIFY, 15200–15399) — server-pushed, not requestable.
|
||
const (
|
||
NotifyTrackResult = 15225
|
||
NotifyStateCaptureRawDark = 15206
|
||
NotifyCalibrationResult = 15256
|
||
NotifyStateAstroGoto = 15211
|
||
NotifyTemperature = 15243
|
||
NotifySDCardInfo = 15203
|
||
NotifyPowerOff = 15229
|
||
)
|