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:
203
dwarfctl/proto/task_center.proto
Normal file
203
dwarfctl/proto/task_center.proto
Normal file
@ -0,0 +1,203 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "github.com/antitbone/dwarfctl/proto;pb";
|
||||
import "notify.proto";
|
||||
import "panorama.proto";
|
||||
import "astro.proto";
|
||||
|
||||
enum TaskId {
|
||||
TASK_ID_IDLE = 0;
|
||||
TASK_ID_PANORAMA_UPLOAD = 1;
|
||||
TASK_ID_ASTRO_MULTI_STACK_THUMBNAIL_GENERATION = 2;
|
||||
TASK_ID_ASTRO_MULTI_STACK = 3;
|
||||
TASK_ID_CAPTURE_CALI_FRAME = 4;
|
||||
}
|
||||
|
||||
enum ExclusiveTaskType {
|
||||
EXCLUSIVE_TYPE_NONE = 0;
|
||||
EXCLUSIVE_TYPE_CAMERA = 1;
|
||||
EXCLUSIVE_TYPE_MOTOR = 2;
|
||||
EXCLUSIVE_TYPE_FOCUS_MOTOR = 4;
|
||||
EXCLUSIVE_TYPE_SYSTEM_IO = 8;
|
||||
EXCLUSIVE_TYPE_SYSTEM_WIFI = 16;
|
||||
}
|
||||
|
||||
message TaskAttr {
|
||||
int32 exclusive_mask = 1;
|
||||
int32 priority = 2;
|
||||
}
|
||||
|
||||
message TaskState {
|
||||
// oneof extendedState
|
||||
notify.OperationState base_state = 1;
|
||||
notify.AstroState astro_extended_state = 2;
|
||||
}
|
||||
|
||||
message TaskParam {
|
||||
// oneof param
|
||||
PanoramaUploadParam panorama_upload = 1;
|
||||
MakeFitsThumbTaskParam make_fits_thumb_task_param = 2;
|
||||
RepostprocessTaskParam repostprocess_task_param = 3;
|
||||
CaptureCaliFrameTaskParam capture_cali_frame_task_param = 4;
|
||||
}
|
||||
|
||||
message ResNotifyTaskState {
|
||||
TaskId task_id = 1;
|
||||
TaskAttr task_attr = 2;
|
||||
TaskState state = 3;
|
||||
TaskParam param = 4;
|
||||
}
|
||||
|
||||
message ReqStartTask {
|
||||
// oneof param
|
||||
TaskId task_id = 1;
|
||||
ReqStartMakeFitsThumb req_make_fits_thumb_param = 2;
|
||||
ReqStartRepostprocess req_repostprocess_param = 3;
|
||||
}
|
||||
|
||||
message ReqStopTask {
|
||||
TaskId task_id = 1;
|
||||
}
|
||||
|
||||
message ResTaskCenter {
|
||||
int32 code = 1;
|
||||
TaskId task_id = 2;
|
||||
}
|
||||
|
||||
message ClientParams {
|
||||
int32 encode_type = 1;
|
||||
}
|
||||
|
||||
message ReqEnterCamera {
|
||||
ClientParams client_param = 3;
|
||||
}
|
||||
|
||||
message ResEnterCamera {
|
||||
int32 code = 1;
|
||||
int32 shooting_mode_id = 2;
|
||||
}
|
||||
|
||||
message ReqSwitchShootingMode {
|
||||
int32 mode = 1;
|
||||
}
|
||||
|
||||
message ResSwitchShootingMode {
|
||||
int32 code = 1;
|
||||
int32 shooting_mode_id = 2;
|
||||
}
|
||||
|
||||
message ReqSwitchShootingTech {
|
||||
int32 tech = 1;
|
||||
}
|
||||
|
||||
message ResSwitchShootingTech {
|
||||
int32 code = 1;
|
||||
int32 shooting_tech_id = 2;
|
||||
}
|
||||
|
||||
message ReqGetDeviceStateInfo {
|
||||
}
|
||||
|
||||
message ExclusiveCameraState {
|
||||
// oneof current_state
|
||||
notify.CaptureRawState capture_raw_state = 1;
|
||||
notify.PhotoState photo_state = 2;
|
||||
notify.BurstState burst_state = 3;
|
||||
notify.RecordState record_state = 4;
|
||||
notify.TimeLapseState timelapse_state = 5;
|
||||
notify.CaptureCaliFrameState capture_cali_frame_state = 6;
|
||||
notify.PanoramaState panorama_state = 7;
|
||||
notify.SentryState sentry_state = 8;
|
||||
}
|
||||
|
||||
message TeleCameraStateInfo {
|
||||
// oneof _cmos_temperature
|
||||
ExclusiveCameraState exclusive_state = 1;
|
||||
notify.StreamType stream_type = 2;
|
||||
double h_fov = 3;
|
||||
double v_fov = 4;
|
||||
uint32 resolution_width = 5;
|
||||
uint32 resolution_height = 6;
|
||||
notify.CmosTemperature cmos_temperature = 7;
|
||||
}
|
||||
|
||||
message WideCameraStateInfo {
|
||||
// oneof _cmos_temperature
|
||||
ExclusiveCameraState exclusive_state = 1;
|
||||
notify.StreamType stream_type = 2;
|
||||
double h_fov = 3;
|
||||
double v_fov = 4;
|
||||
uint32 resolution_width = 5;
|
||||
uint32 resolution_height = 6;
|
||||
notify.CmosTemperature cmos_temperature = 7;
|
||||
}
|
||||
|
||||
message ExclusiveFocusMotorState {
|
||||
// oneof current_state
|
||||
notify.AstroAutoFocusState astro_auto_focus_state = 1;
|
||||
notify.NormalAutoFocusState normal_auto_focus_state = 2;
|
||||
notify.AstroAutoFocusFastState astro_auto_focus_fast_state = 3;
|
||||
notify.AreaAutoFocusState area_auto_focus_state = 4;
|
||||
}
|
||||
|
||||
message FocusMotorStateInfo {
|
||||
// oneof _focus_position
|
||||
ExclusiveFocusMotorState exclusive_state = 1;
|
||||
notify.FocusPosition focus_position = 2;
|
||||
}
|
||||
|
||||
message ExclusiveMotionMotorState {
|
||||
// oneof current_state
|
||||
notify.AstroCalibrationState astro_calibration_state = 1;
|
||||
notify.AstroGotoState astro_goto_state = 2;
|
||||
notify.AstroTrackingState astro_tracking_state = 3;
|
||||
notify.NormalTrackState normal_track_state = 4;
|
||||
notify.OneClickGotoState one_click_goto_state = 5;
|
||||
notify.EqSolvingState eq_state = 6;
|
||||
notify.SentryState sentry_state = 7;
|
||||
notify.SkyTargetFinderState sky_target_finder_state = 8;
|
||||
}
|
||||
|
||||
message MotionMotorStateInfo {
|
||||
ExclusiveMotionMotorState exclusive_state = 1;
|
||||
notify.SentryAutoHand sentry_auto_hand = 2;
|
||||
}
|
||||
|
||||
message DeviceStateInfo {
|
||||
notify.RgbState rgb_state = 1;
|
||||
notify.PowerIndState power_ind_state = 2;
|
||||
notify.ChargingState charging_state = 3;
|
||||
notify.StorageInfo storage_info = 4;
|
||||
notify.MTPState mtp_state = 5;
|
||||
notify.CPUMode cpu_mode = 6;
|
||||
notify.Temperature temperature = 7;
|
||||
notify.BodyStatus body_status = 8;
|
||||
notify.BatteryInfo battery_info = 9;
|
||||
notify.CalibrationResult calibration_result = 10;
|
||||
notify.PictureMatching picture_matching = 11;
|
||||
notify.AutoShutdown auto_shutdown = 12;
|
||||
notify.LensDefog lens_defog = 13;
|
||||
notify.AutoCooling auto_cooling = 14;
|
||||
}
|
||||
|
||||
message ConnectionStateInfo {
|
||||
notify.HostSlaveMode host_slave_mode = 1;
|
||||
}
|
||||
|
||||
message ShootingModeAndTech {
|
||||
int32 shooting_mode = 1;
|
||||
int32 parent_shooting_mode = 2;
|
||||
repeated int32 shooting_techs = 3;
|
||||
}
|
||||
|
||||
message ResGetDeviceStateInfo {
|
||||
int32 shooting_mode = 1;
|
||||
TeleCameraStateInfo tele_camera_state_info = 2;
|
||||
WideCameraStateInfo wide_camera_state_info = 3;
|
||||
FocusMotorStateInfo focus_motor_state_info = 4;
|
||||
MotionMotorStateInfo motion_motor_state_info = 5;
|
||||
DeviceStateInfo device_state_info = 6;
|
||||
int32 code = 7;
|
||||
ConnectionStateInfo connection_state_info = 8;
|
||||
repeated ShootingModeAndTech shooting_mode_and_techs = 9;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user