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
This commit is contained in:
243
dwarfctl/internal/api/commands.go
Normal file
243
dwarfctl/internal/api/commands.go
Normal file
@ -0,0 +1,243 @@
|
||||
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
|
||||
)
|
||||
Reference in New Issue
Block a user