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:
517
dwarfctl/proto/notify.proto
Normal file
517
dwarfctl/proto/notify.proto
Normal file
@ -0,0 +1,517 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "github.com/antitbone/dwarfctl/proto;pb";
|
||||
|
||||
import "base.proto";
|
||||
|
||||
enum OperationState {
|
||||
OPERATION_STATE_IDLE = 0;
|
||||
OPERATION_STATE_RUNNING = 1;
|
||||
OPERATION_STATE_STOPPING = 2;
|
||||
OPERATION_STATE_STOPPED = 3;
|
||||
}
|
||||
|
||||
enum AstroState {
|
||||
ASTRO_STATE_IDLE = 0;
|
||||
ASTRO_STATE_RUNNING = 1;
|
||||
ASTRO_STATE_STOPPING = 2;
|
||||
ASTRO_STATE_STOPPED = 3;
|
||||
ASTRO_STATE_PLATE_SOLVING = 4;
|
||||
}
|
||||
|
||||
enum SentryModeState {
|
||||
SENTRY_MODE_STATE_IDLE = 0;
|
||||
SENTRY_MODE_STATE_INIT = 1;
|
||||
SENTRY_MODE_STATE_DETECT = 2;
|
||||
SENTRY_MODE_STATE_TRACK = 3;
|
||||
SENTRY_MODE_STATE_TRACK_FINISH = 4;
|
||||
SENTRY_MODE_STATE_STOPPING = 5;
|
||||
}
|
||||
|
||||
enum SentryObjectType {
|
||||
SENTRY_OBJECT_TYPE_UNKNOWN = 0;
|
||||
SENTRY_OBJECT_TYPE_UFO = 1;
|
||||
SENTRY_OBJECT_TYPE_BIRD = 2;
|
||||
SENTRY_OBJECT_TYPE_PERSON = 3;
|
||||
SENTRY_OBJECT_TYPE_ANIMAL = 4;
|
||||
SENTRY_OBJECT_TYPE_VEHICLE = 5;
|
||||
SENTRY_OBJECT_TYPE_FLYING = 6;
|
||||
SENTRY_OBJECT_TYPE_BOAT = 7;
|
||||
}
|
||||
|
||||
message PictureMatching {
|
||||
uint32 x = 1;
|
||||
uint32 y = 2;
|
||||
uint32 width = 3;
|
||||
uint32 height = 4;
|
||||
}
|
||||
|
||||
message StorageInfo {
|
||||
uint32 available_size = 1;
|
||||
uint32 total_size = 2;
|
||||
int32 storage_type = 3;
|
||||
bool is_valid = 4;
|
||||
}
|
||||
|
||||
message Temperature {
|
||||
int32 code = 1;
|
||||
int32 temperature = 2;
|
||||
}
|
||||
|
||||
message CmosTemperature {
|
||||
// oneof _temperature
|
||||
int32 temperature = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message RecordTime {
|
||||
uint32 record_time = 1;
|
||||
uint32 camera_type = 2;
|
||||
}
|
||||
|
||||
message TimeLapseOutTime {
|
||||
uint32 interval = 1;
|
||||
uint32 out_time = 2;
|
||||
uint32 total_time = 3;
|
||||
uint32 camera_type = 4;
|
||||
}
|
||||
|
||||
message OperationStateNotify {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message AstroCalibrationState {
|
||||
AstroState state = 1;
|
||||
int32 plate_solving_times = 2;
|
||||
}
|
||||
|
||||
message AstroGotoState {
|
||||
AstroState state = 1;
|
||||
string target_name = 2;
|
||||
}
|
||||
|
||||
message AstroTrackingState {
|
||||
OperationState state = 1;
|
||||
string target_name = 2;
|
||||
}
|
||||
|
||||
message ProgressCaptureRawDark {
|
||||
int32 progress = 1;
|
||||
int32 remaining_time = 2;
|
||||
int32 camera_type = 3;
|
||||
}
|
||||
|
||||
message ProgressCaptureRawLiveStacking {
|
||||
// oneof _shooting_time
|
||||
// oneof _stacked_time
|
||||
int32 total_count = 1;
|
||||
int32 update_type = 2;
|
||||
int32 current_count = 3;
|
||||
int32 stacked_count = 4;
|
||||
int32 exp_index = 5;
|
||||
int32 gain_index = 6;
|
||||
string target_name = 7;
|
||||
int32 camera_type = 8;
|
||||
int32 shooting_time = 9;
|
||||
int32 stacked_time = 10;
|
||||
}
|
||||
|
||||
message Param {
|
||||
repeated CommonParam param = 1;
|
||||
}
|
||||
|
||||
message BurstProgress {
|
||||
uint32 total_count = 1;
|
||||
uint32 completed_count = 2;
|
||||
uint32 camera_type = 3;
|
||||
}
|
||||
|
||||
message PanoramaProgress {
|
||||
int32 total_count = 1;
|
||||
int32 completed_count = 2;
|
||||
uint32 camera_type = 3;
|
||||
}
|
||||
|
||||
message RgbState {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
message PowerIndState {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
message ChargingState {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
message BatteryInfo {
|
||||
int32 percentage = 1;
|
||||
}
|
||||
|
||||
message HostSlaveMode {
|
||||
int32 mode = 1;
|
||||
bool lock = 2;
|
||||
}
|
||||
|
||||
message MTPState {
|
||||
int32 mode = 1;
|
||||
}
|
||||
|
||||
message TrackResult {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
int32 w = 3;
|
||||
int32 h = 4;
|
||||
int32 id = 5;
|
||||
}
|
||||
|
||||
message CPUMode {
|
||||
int32 mode = 1;
|
||||
}
|
||||
|
||||
message AstroTrackingSpecialState {
|
||||
OperationState state = 1;
|
||||
string target_name = 2;
|
||||
int32 index = 3;
|
||||
}
|
||||
|
||||
message PowerOff {
|
||||
}
|
||||
|
||||
message AlbumUpdate {
|
||||
int32 media_type = 1;
|
||||
}
|
||||
|
||||
message SentryState {
|
||||
SentryModeState state = 1;
|
||||
SentryObjectType object_type = 2;
|
||||
}
|
||||
|
||||
message OneClickGotoState {
|
||||
// oneof current_state
|
||||
AstroAutoFocusState astro_auto_focus_state = 1;
|
||||
AstroCalibrationState astro_calibration_state = 2;
|
||||
AstroGotoState astro_goto_state = 3;
|
||||
AstroTrackingState astro_tracking_state = 4;
|
||||
}
|
||||
|
||||
message StreamType {
|
||||
int32 stream_type = 1;
|
||||
int32 cam_id = 2;
|
||||
}
|
||||
|
||||
message MultiTrackResult {
|
||||
repeated TrackResult results = 1;
|
||||
}
|
||||
|
||||
message EqSolvingState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message LongExpPhotoProgress {
|
||||
double total_time = 1;
|
||||
double exposured_time = 2;
|
||||
uint32 camera_type = 3;
|
||||
}
|
||||
|
||||
message ShootingScheduleResultAndState {
|
||||
string schedule_id = 1;
|
||||
int32 result = 2;
|
||||
int32 state = 3;
|
||||
}
|
||||
|
||||
message ShootingTaskState {
|
||||
string schedule_task_id = 1;
|
||||
int32 state = 2;
|
||||
int32 code = 3;
|
||||
}
|
||||
|
||||
message SkySeacherState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message ProgressAiEnhance {
|
||||
int32 progress = 1;
|
||||
int32 total_time = 2;
|
||||
}
|
||||
|
||||
message CommonProgress {
|
||||
enum ProgressType {
|
||||
PROGRESS_TYPE_INITING = 0;
|
||||
PROGRESS_TYPE_MOSAIC_MOVING = 1;
|
||||
}
|
||||
int32 current = 1;
|
||||
int32 total = 2;
|
||||
CommonProgress.ProgressType progress_type = 3;
|
||||
}
|
||||
|
||||
message CalibrationResult {
|
||||
double azi = 1;
|
||||
double alt = 2;
|
||||
}
|
||||
|
||||
message FocusPosition {
|
||||
int32 pos = 1;
|
||||
}
|
||||
|
||||
message SentryAutoHand {
|
||||
int32 mode = 1;
|
||||
}
|
||||
|
||||
message PanoramaStitchUploadComplete {
|
||||
int32 code = 1;
|
||||
string user_id = 2;
|
||||
string busi_no = 3;
|
||||
string panorama_name = 4;
|
||||
string mac = 5;
|
||||
}
|
||||
|
||||
message PanoramaCompressionComplete {
|
||||
int32 code = 1;
|
||||
string panorama_name = 2;
|
||||
string zip_file_path = 3;
|
||||
string zip_file_md5 = 4;
|
||||
uint64 zip_file_size = 5;
|
||||
string stitch_param = 6;
|
||||
}
|
||||
|
||||
message PanoramaCompressionProgress {
|
||||
string panorama_name = 1;
|
||||
uint32 total_files_num = 2;
|
||||
uint32 compressed_files_num = 3;
|
||||
}
|
||||
|
||||
message PanoramaUploadCompressionProgress {
|
||||
string user_id = 1;
|
||||
string busi_no = 2;
|
||||
string panorama_name = 3;
|
||||
string mac = 4;
|
||||
uint32 total_files_num = 5;
|
||||
uint32 compressed_files_num = 6;
|
||||
double speed = 7;
|
||||
}
|
||||
|
||||
message PanoramaUploadProgress {
|
||||
string user_id = 1;
|
||||
string busi_no = 2;
|
||||
string panorama_name = 3;
|
||||
string mac = 4;
|
||||
uint64 total_size = 5;
|
||||
uint64 uploaded_size = 6;
|
||||
double speed = 7;
|
||||
}
|
||||
|
||||
message PanoramaCurrentUploadState {
|
||||
int32 code = 1;
|
||||
string user_id = 2;
|
||||
string busi_no = 3;
|
||||
string panorama_name = 4;
|
||||
string mac = 5;
|
||||
uint32 total_files_num = 6;
|
||||
uint32 compressed_files_num = 7;
|
||||
uint64 total_size = 8;
|
||||
uint64 uploaded_size = 9;
|
||||
uint32 step = 10;
|
||||
}
|
||||
|
||||
message LowTempProtectionMode {
|
||||
int32 mode = 1;
|
||||
}
|
||||
|
||||
message StateSystemResourceOccupation {
|
||||
enum TaskId {
|
||||
IDLE = 0;
|
||||
PANORAMA_UPLOAD = 1;
|
||||
ASTRO_MULTI_STACK = 2;
|
||||
}
|
||||
StateSystemResourceOccupation.TaskId task_id = 1;
|
||||
OperationState state = 2;
|
||||
}
|
||||
|
||||
message BodyStatus {
|
||||
enum BodyStatusEnum {
|
||||
UNKNOWN = 0;
|
||||
EQ_MODE = 1;
|
||||
AZI_MODE = 2;
|
||||
}
|
||||
BodyStatus.BodyStatusEnum body_status = 1;
|
||||
}
|
||||
|
||||
message ProgressCaptureMosaic {
|
||||
int32 total_count = 1;
|
||||
int32 update_type = 2;
|
||||
int32 current_count = 3;
|
||||
int32 stacked_count = 4;
|
||||
int32 exp_index = 5;
|
||||
int32 gain_index = 6;
|
||||
string target_name = 7;
|
||||
int32 horizontal_scale = 8;
|
||||
int32 vertical_scale = 9;
|
||||
int32 rotation = 10;
|
||||
int32 fov_id = 11;
|
||||
int32 fov_total = 12;
|
||||
}
|
||||
|
||||
message Wb {
|
||||
uint64 mode = 1;
|
||||
int32 ct = 2;
|
||||
int32 scene = 3;
|
||||
int32 camera_type = 4;
|
||||
}
|
||||
|
||||
message GeneralIntParam {
|
||||
uint64 param_id = 1;
|
||||
int32 mode = 2;
|
||||
int32 value = 3;
|
||||
}
|
||||
|
||||
message GeneralFloatParam {
|
||||
uint64 param_id = 1;
|
||||
float value = 2;
|
||||
}
|
||||
|
||||
message GeneralBoolParams {
|
||||
uint64 param_id = 1;
|
||||
bool value = 2;
|
||||
}
|
||||
|
||||
message SwitchShootingMode {
|
||||
int32 state = 1;
|
||||
int32 source_mode = 2;
|
||||
int32 dst_mode = 3;
|
||||
}
|
||||
|
||||
message SwitchCropRatioState {
|
||||
int32 state = 1;
|
||||
int32 crop_ratio = 2;
|
||||
}
|
||||
|
||||
message ResolutionParam {
|
||||
uint64 param_id = 1;
|
||||
int32 current_res_value = 2;
|
||||
int32 current_fps_value = 3;
|
||||
repeated int32 supported_fps_list = 4;
|
||||
repeated int32 supported_resolution_list = 5;
|
||||
}
|
||||
|
||||
message CaptureRawState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message PhotoState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message BurstState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message RecordState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message TimeLapseState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message CaptureRawDarkState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message PanoramaState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message AstroAutoFocusState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message NormalAutoFocusState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message AstroAutoFocusFastState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message AreaAutoFocusState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message DualCameraLinkageState {
|
||||
OperationState state = 1;
|
||||
}
|
||||
|
||||
message NormalTrackState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message SwitchResolutionFpsState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
}
|
||||
|
||||
message CaptureCaliFrameState {
|
||||
OperationState state = 1;
|
||||
int32 camera_type = 2;
|
||||
int32 cali_frame_type = 3;
|
||||
}
|
||||
|
||||
message CaptureCaliFrameProgress {
|
||||
int32 progress = 1;
|
||||
int32 camera_type = 2;
|
||||
int32 cali_frame_type = 3;
|
||||
}
|
||||
|
||||
message DeviceAttitude {
|
||||
double pitch = 1;
|
||||
double yaw = 2;
|
||||
double roll = 3;
|
||||
}
|
||||
|
||||
message SkyTargetFinderState {
|
||||
OperationState state = 1;
|
||||
int32 scene_type = 2;
|
||||
}
|
||||
|
||||
message PanoFramingThumbnailUpdateNotify {
|
||||
bytes webp_data = 1;
|
||||
}
|
||||
|
||||
message PanoFramingRectUpdateNotify {
|
||||
double norm_x_tl = 1;
|
||||
double norm_y_tl = 2;
|
||||
double norm_x_br = 3;
|
||||
double norm_y_br = 4;
|
||||
double norm_limit_x_left = 5;
|
||||
double norm_limit_y_top = 6;
|
||||
double norm_limit_x_right = 7;
|
||||
double norm_limit_y_bottom = 8;
|
||||
double rect_hor_fov = 9;
|
||||
double rect_ver_fov = 10;
|
||||
int32 error_code = 11;
|
||||
}
|
||||
|
||||
message PanoFramingStateNotify {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
message AutoShutdown {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
message LensDefog {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
message AutoCooling {
|
||||
int32 state = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user